@lodestar/beacon-node 1.43.0-dev.ade910fc78 → 1.43.0-dev.ca1fc40294
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.
- package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +1 -4
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +2 -2
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +1 -4
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/GetBlobsTracker.d.ts +1 -1
- package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
- package/lib/chain/GetBlobsTracker.js +1 -2
- package/lib/chain/GetBlobsTracker.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/interface.d.ts +4 -4
- package/lib/chain/archiveStore/interface.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +2 -4
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +2 -2
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +110 -58
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +23 -31
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +19 -26
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.js +1 -1
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +3 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +20 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -0
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +6 -4
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +1 -1
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +14 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js +25 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -0
- package/lib/chain/chain.d.ts +3 -3
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +16 -32
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +16 -4
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +5 -0
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/attestationError.d.ts +8 -1
- package/lib/chain/errors/attestationError.d.ts.map +1 -1
- package/lib/chain/errors/attestationError.js +4 -0
- package/lib/chain/errors/attestationError.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +9 -13
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +22 -16
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts +3 -9
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +5 -32
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -8
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +29 -19
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/errors.d.ts +1 -11
- package/lib/chain/regen/errors.d.ts.map +1 -1
- package/lib/chain/regen/errors.js +0 -2
- package/lib/chain/regen/errors.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +6 -11
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/queued.d.ts +6 -10
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +3 -10
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts +0 -5
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +0 -8
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +1 -7
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -9
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +0 -6
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/stateCache/types.js.map +1 -1
- package/lib/chain/validation/aggregateAndProof.js +12 -0
- package/lib/chain/validation/aggregateAndProof.js.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +12 -0
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +10 -10
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +4 -3
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/db/repositories/executionPayloadEnvelopeArchive.js +1 -1
- package/lib/db/repositories/executionPayloadEnvelopeArchive.js.map +1 -1
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +21 -14
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +1 -0
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +6 -0
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/execution/engine/types.d.ts +20 -0
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +18 -0
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +3 -2
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/network.js +1 -1
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +22 -6
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +4 -2
- package/lib/node/nodejs.js.map +1 -1
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +16 -3
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +16 -16
- package/src/api/impl/beacon/blocks/index.ts +1 -4
- package/src/api/impl/beacon/state/utils.ts +2 -2
- package/src/api/impl/validator/index.ts +3 -6
- package/src/chain/GetBlobsTracker.ts +1 -2
- package/src/chain/archiveStore/archiveStore.ts +5 -5
- package/src/chain/archiveStore/interface.ts +4 -4
- package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +6 -8
- package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
- package/src/chain/blocks/importBlock.ts +22 -35
- package/src/chain/blocks/importExecutionPayload.ts +20 -26
- package/src/chain/blocks/index.ts +1 -1
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +27 -0
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +6 -5
- package/src/chain/blocks/types.ts +1 -1
- package/src/chain/blocks/verifyPayloadsDataAvailability.ts +38 -0
- package/src/chain/chain.ts +23 -48
- package/src/chain/emitter.ts +15 -3
- package/src/chain/errors/attestationError.ts +6 -1
- package/src/chain/forkChoice/index.ts +6 -18
- package/src/chain/interface.ts +2 -2
- package/src/chain/prepareNextSlot.ts +25 -16
- package/src/chain/produceBlock/computeNewStateRoot.ts +6 -43
- package/src/chain/produceBlock/produceBlockBody.ts +40 -20
- package/src/chain/regen/errors.ts +1 -6
- package/src/chain/regen/interface.ts +6 -11
- package/src/chain/regen/queued.ts +6 -14
- package/src/chain/regen/regen.ts +0 -8
- package/src/chain/stateCache/persistentCheckpointsCache.ts +5 -15
- package/src/chain/stateCache/types.ts +0 -3
- package/src/chain/validation/aggregateAndProof.ts +13 -0
- package/src/chain/validation/attestation.ts +13 -0
- package/src/chain/validation/executionPayloadEnvelope.ts +10 -10
- package/src/chain/validation/payloadAttestationMessage.ts +5 -3
- package/src/db/repositories/executionPayloadEnvelopeArchive.ts +1 -1
- package/src/execution/engine/http.ts +21 -14
- package/src/execution/engine/interface.ts +1 -0
- package/src/execution/engine/mock.ts +8 -1
- package/src/execution/engine/types.ts +41 -0
- package/src/network/network.ts +1 -1
- package/src/network/processor/gossipHandlers.ts +26 -10
- package/src/node/nodejs.ts +4 -2
- package/src/util/sszBytes.ts +21 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
-
import {
|
|
3
|
+
import {getSafeExecutionBlockHash} from "@lodestar/fork-choice";
|
|
4
4
|
import {ForkPostBellatrix, ForkSeq, SLOTS_PER_EPOCH, isForkPostBellatrix} from "@lodestar/params";
|
|
5
5
|
import {
|
|
6
6
|
IBeaconStateView,
|
|
@@ -8,8 +8,9 @@ import {
|
|
|
8
8
|
computeEpochAtSlot,
|
|
9
9
|
computeTimeAtSlot,
|
|
10
10
|
isStatePostBellatrix,
|
|
11
|
+
isStatePostGloas,
|
|
11
12
|
} from "@lodestar/state-transition";
|
|
12
|
-
import {Slot} from "@lodestar/types";
|
|
13
|
+
import {Bytes32, Slot} from "@lodestar/types";
|
|
13
14
|
import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils";
|
|
14
15
|
import {GENESIS_SLOT, ZERO_HASH_HEX} from "../constants/constants.js";
|
|
15
16
|
import {BuilderStatus} from "../execution/builder/http.js";
|
|
@@ -81,6 +82,8 @@ export class PrepareNextSlotScheduler {
|
|
|
81
82
|
// calling updateHead() here before we produce a block to reduce reorg possibility
|
|
82
83
|
const headBlock = this.chain.recomputeForkChoiceHead(ForkchoiceCaller.prepareNextSlot);
|
|
83
84
|
const {slot: headSlot, blockRoot: headRoot} = headBlock;
|
|
85
|
+
// may be updated below if we predict a proposer-boost-reorg
|
|
86
|
+
let updatedHeadRoot = headRoot;
|
|
84
87
|
|
|
85
88
|
// PS: previously this was comparing slots, but that gave no leway on the skipped
|
|
86
89
|
// slots on epoch bounday. Making it more fluid.
|
|
@@ -123,7 +126,6 @@ export class PrepareNextSlotScheduler {
|
|
|
123
126
|
const proposerIndex = prepareState.getBeaconProposer(prepareSlot);
|
|
124
127
|
const feeRecipient = this.chain.beaconProposerCache.get(proposerIndex);
|
|
125
128
|
let updatedPrepareState = prepareState;
|
|
126
|
-
let updatedHeadRoot = headRoot;
|
|
127
129
|
|
|
128
130
|
if (feeRecipient) {
|
|
129
131
|
// If we are proposing next slot, we need to predict if we can proposer-boost-reorg or not
|
|
@@ -156,25 +158,39 @@ export class PrepareNextSlotScheduler {
|
|
|
156
158
|
this.logger.error("Builder disabled as the check status api failed", {prepareSlot}, e as Error);
|
|
157
159
|
});
|
|
158
160
|
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!isStatePostBellatrix(updatedPrepareState)) {
|
|
164
|
+
throw new Error("Expected Bellatrix state for payload attributes");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let parentBlockHash: Bytes32;
|
|
168
|
+
if (isStatePostGloas(updatedPrepareState)) {
|
|
169
|
+
parentBlockHash = this.chain.forkChoice.shouldExtendPayload(updatedHeadRoot)
|
|
170
|
+
? updatedPrepareState.latestExecutionPayloadBid.blockHash
|
|
171
|
+
: updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
|
|
172
|
+
} else {
|
|
173
|
+
parentBlockHash = updatedPrepareState.latestExecutionPayloadHeader.blockHash;
|
|
174
|
+
}
|
|
159
175
|
|
|
176
|
+
if (feeRecipient) {
|
|
160
177
|
const preparationTime =
|
|
161
178
|
computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
|
|
162
179
|
this.metrics?.blockPayload.payloadAdvancePrepTime.observe(preparationTime);
|
|
163
|
-
if (!isStatePostBellatrix(updatedPrepareState)) {
|
|
164
|
-
throw new Error("Expected Bellatrix state for payload preparation");
|
|
165
|
-
}
|
|
166
180
|
|
|
167
181
|
const safeBlockHash = getSafeExecutionBlockHash(this.chain.forkChoice);
|
|
168
182
|
const finalizedBlockHash =
|
|
169
183
|
this.chain.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
|
|
184
|
+
|
|
170
185
|
// awaiting here instead of throwing an async call because there is no other task
|
|
171
|
-
// left for scheduler and this gives nice
|
|
186
|
+
// left for scheduler and this gives nice semantics to catch and log errors in the
|
|
172
187
|
// try/catch wrapper here.
|
|
173
188
|
await prepareExecutionPayload(
|
|
174
189
|
this.chain,
|
|
175
190
|
this.logger,
|
|
176
191
|
fork as ForkPostBellatrix, // State is of execution type
|
|
177
192
|
fromHex(updatedHeadRoot),
|
|
193
|
+
parentBlockHash,
|
|
178
194
|
safeBlockHash,
|
|
179
195
|
finalizedBlockHash,
|
|
180
196
|
updatedPrepareState,
|
|
@@ -187,10 +203,6 @@ export class PrepareNextSlotScheduler {
|
|
|
187
203
|
});
|
|
188
204
|
}
|
|
189
205
|
|
|
190
|
-
if (!isStatePostBellatrix(updatedPrepareState)) {
|
|
191
|
-
throw new Error("Expected Bellatrix state for payload attributes");
|
|
192
|
-
}
|
|
193
|
-
|
|
194
206
|
this.computeStateHashTreeRoot(updatedPrepareState, isEpochTransition);
|
|
195
207
|
|
|
196
208
|
// If emitPayloadAttributes is true emit a SSE payloadAttributes event
|
|
@@ -202,6 +214,7 @@ export class PrepareNextSlotScheduler {
|
|
|
202
214
|
prepareState: updatedPrepareState,
|
|
203
215
|
prepareSlot,
|
|
204
216
|
parentBlockRoot: fromHex(headRoot),
|
|
217
|
+
parentBlockHash,
|
|
205
218
|
// The likely consumers of this API are builders and will anyway ignore the
|
|
206
219
|
// feeRecipient, so just pass zero hash for now till a real use case arises
|
|
207
220
|
feeRecipient: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
@@ -217,11 +230,7 @@ export class PrepareNextSlotScheduler {
|
|
|
217
230
|
// + if next slot is a skipped slot, it'd help getting target checkpoint state faster to validate attestations
|
|
218
231
|
if (isEpochTransition) {
|
|
219
232
|
this.metrics?.precomputeNextEpochTransition.count.inc({result: "success"}, 1);
|
|
220
|
-
|
|
221
|
-
// Pre-Gloas: payloadStatus is always FULL → payloadPresent = true
|
|
222
|
-
// Post-Gloas: FULL → true, EMPTY → false, PENDING → false (conservative, treat as block state)
|
|
223
|
-
const payloadPresent = headBlock.payloadStatus === PayloadStatus.FULL;
|
|
224
|
-
const previousHits = this.chain.regen.updatePreComputedCheckpoint(headRoot, nextEpoch, payloadPresent);
|
|
233
|
+
const previousHits = this.chain.regen.updatePreComputedCheckpoint(headRoot, nextEpoch);
|
|
225
234
|
if (previousHits === 0) {
|
|
226
235
|
this.metrics?.precomputeNextEpochTransition.waste.inc();
|
|
227
236
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DataAvailabilityStatus,
|
|
3
3
|
ExecutionPayloadStatus,
|
|
4
|
-
G2_POINT_AT_INFINITY,
|
|
5
4
|
IBeaconStateView,
|
|
6
|
-
IBeaconStateViewGloas,
|
|
7
5
|
StateHashTreeRootSource,
|
|
8
6
|
} from "@lodestar/state-transition";
|
|
9
|
-
import {BeaconBlock, BlindedBeaconBlock, Gwei, Root
|
|
7
|
+
import {BeaconBlock, BlindedBeaconBlock, Gwei, Root} from "@lodestar/types";
|
|
10
8
|
import {ZERO_HASH} from "../../constants/index.js";
|
|
11
9
|
import {Metrics} from "../../metrics/index.js";
|
|
12
10
|
|
|
@@ -19,11 +17,11 @@ export function computeNewStateRoot(
|
|
|
19
17
|
metrics: Metrics | null,
|
|
20
18
|
state: IBeaconStateView,
|
|
21
19
|
block: BeaconBlock | BlindedBeaconBlock
|
|
22
|
-
): {newStateRoot: Root; proposerReward: Gwei;
|
|
20
|
+
): {newStateRoot: Root; proposerReward: Gwei; postState: IBeaconStateView} {
|
|
23
21
|
// Set signature to zero to re-use stateTransition() function which requires the SignedBeaconBlock type
|
|
24
22
|
const blockEmptySig = {message: block, signature: ZERO_HASH};
|
|
25
23
|
|
|
26
|
-
const
|
|
24
|
+
const postState = state.stateTransition(
|
|
27
25
|
blockEmptySig,
|
|
28
26
|
{
|
|
29
27
|
// ExecutionPayloadStatus.valid: Assume payload valid, it has been produced by a trusted EL
|
|
@@ -42,49 +40,14 @@ export function computeNewStateRoot(
|
|
|
42
40
|
{metrics}
|
|
43
41
|
);
|
|
44
42
|
|
|
45
|
-
const {attestations, syncAggregate, slashing} =
|
|
43
|
+
const {attestations, syncAggregate, slashing} = postState.proposerRewards;
|
|
46
44
|
const proposerReward = BigInt(attestations + syncAggregate + slashing);
|
|
47
45
|
|
|
48
46
|
const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer({
|
|
49
47
|
source: StateHashTreeRootSource.computeNewStateRoot,
|
|
50
48
|
});
|
|
51
|
-
const newStateRoot =
|
|
49
|
+
const newStateRoot = postState.hashTreeRoot();
|
|
52
50
|
hashTreeRootTimer?.();
|
|
53
51
|
|
|
54
|
-
return {newStateRoot, proposerReward,
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Compute the state root after processing an execution payload envelope.
|
|
59
|
-
* Similar to `computeNewStateRoot` but for payload envelope processing.
|
|
60
|
-
*
|
|
61
|
-
*/
|
|
62
|
-
export function computePayloadEnvelopeStateRoot(
|
|
63
|
-
metrics: Metrics | null,
|
|
64
|
-
postBlockState: IBeaconStateViewGloas,
|
|
65
|
-
envelope: gloas.ExecutionPayloadEnvelope
|
|
66
|
-
): Root {
|
|
67
|
-
const signedEnvelope: gloas.SignedExecutionPayloadEnvelope = {
|
|
68
|
-
message: envelope,
|
|
69
|
-
signature: G2_POINT_AT_INFINITY,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const processEnvelopeTimer = metrics?.blockPayload.executionPayloadEnvelopeProcessingTime.startTimer();
|
|
73
|
-
const postPayloadState = postBlockState.processExecutionPayloadEnvelope(signedEnvelope, {
|
|
74
|
-
// Signature is zero-ed (G2_POINT_AT_INFINITY), skip verification
|
|
75
|
-
verifySignature: false,
|
|
76
|
-
// State root is being computed here, the envelope doesn't have it yet
|
|
77
|
-
verifyStateRoot: false,
|
|
78
|
-
// Preserve cache in source state, since the resulting state is not added to the state cache
|
|
79
|
-
dontTransferCache: true,
|
|
80
|
-
});
|
|
81
|
-
processEnvelopeTimer?.();
|
|
82
|
-
|
|
83
|
-
const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer({
|
|
84
|
-
source: StateHashTreeRootSource.computePayloadEnvelopeStateRoot,
|
|
85
|
-
});
|
|
86
|
-
const stateRoot = postPayloadState.hashTreeRoot();
|
|
87
|
-
hashTreeRootTimer?.();
|
|
88
|
-
|
|
89
|
-
return stateRoot;
|
|
52
|
+
return {newStateRoot, proposerReward, postState};
|
|
90
53
|
}
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
IBeaconStateView,
|
|
20
20
|
type IBeaconStateViewBellatrix,
|
|
21
21
|
computeTimeAtSlot,
|
|
22
|
-
isParentBlockFull,
|
|
23
22
|
isStatePostBellatrix,
|
|
24
23
|
isStatePostCapella,
|
|
25
24
|
isStatePostGloas,
|
|
@@ -47,8 +46,9 @@ import {
|
|
|
47
46
|
electra,
|
|
48
47
|
fulu,
|
|
49
48
|
gloas,
|
|
49
|
+
ssz,
|
|
50
50
|
} from "@lodestar/types";
|
|
51
|
-
import {Logger, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
51
|
+
import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
52
52
|
import {ZERO_HASH_HEX} from "../../constants/index.js";
|
|
53
53
|
import {numToQuantity} from "../../execution/engine/utils.js";
|
|
54
54
|
import {
|
|
@@ -111,12 +111,6 @@ export type ProduceFullGloas = {
|
|
|
111
111
|
executionRequests: electra.ExecutionRequests;
|
|
112
112
|
blobsBundle: BlobsBundle<ForkPostGloas>;
|
|
113
113
|
cells: fulu.Cell[][];
|
|
114
|
-
/**
|
|
115
|
-
* Cached payload envelope state root computed during block production.
|
|
116
|
-
* This is the state root after running `processExecutionPayloadEnvelope` on the
|
|
117
|
-
* post-block state, and later used to construct the `ExecutionPayloadEnvelope`.
|
|
118
|
-
*/
|
|
119
|
-
payloadEnvelopeStateRoot: Root;
|
|
120
114
|
};
|
|
121
115
|
export type ProduceFullFulu = {
|
|
122
116
|
type: BlockType.Full;
|
|
@@ -220,11 +214,15 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
220
214
|
});
|
|
221
215
|
|
|
222
216
|
// Get execution payload from EL
|
|
217
|
+
const parentBlockHash = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot))
|
|
218
|
+
? currentState.latestExecutionPayloadBid.blockHash
|
|
219
|
+
: currentState.latestExecutionPayloadBid.parentBlockHash;
|
|
223
220
|
const prepareRes = await prepareExecutionPayload(
|
|
224
221
|
this,
|
|
225
222
|
this.logger,
|
|
226
223
|
fork,
|
|
227
224
|
parentBlockRoot,
|
|
225
|
+
parentBlockHash,
|
|
228
226
|
safeBlockHash,
|
|
229
227
|
finalizedBlockHash ?? ZERO_HASH_HEX,
|
|
230
228
|
currentState,
|
|
@@ -261,8 +259,8 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
261
259
|
|
|
262
260
|
// Create self-build execution payload bid
|
|
263
261
|
const bid: gloas.ExecutionPayloadBid = {
|
|
264
|
-
parentBlockHash
|
|
265
|
-
parentBlockRoot
|
|
262
|
+
parentBlockHash,
|
|
263
|
+
parentBlockRoot,
|
|
266
264
|
blockHash: executionPayload.blockHash,
|
|
267
265
|
prevRandao: currentState.getRandaoMix(currentState.epoch),
|
|
268
266
|
feeRecipient: executionPayload.feeRecipient,
|
|
@@ -272,6 +270,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
272
270
|
value: 0,
|
|
273
271
|
executionPayment: 0,
|
|
274
272
|
blobKzgCommitments: blobsBundle.commitments,
|
|
273
|
+
executionRequestsRoot: ssz.electra.ExecutionRequests.hashTreeRoot(executionRequests),
|
|
275
274
|
};
|
|
276
275
|
const signedBid: gloas.SignedExecutionPayloadBid = {
|
|
277
276
|
message: bid,
|
|
@@ -340,6 +339,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
340
339
|
this.logger,
|
|
341
340
|
fork,
|
|
342
341
|
parentBlockRoot,
|
|
342
|
+
currentState.latestExecutionPayloadHeader.blockHash,
|
|
343
343
|
safeBlockHash,
|
|
344
344
|
finalizedBlockHash ?? ZERO_HASH_HEX,
|
|
345
345
|
currentState,
|
|
@@ -448,6 +448,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
448
448
|
this.logger,
|
|
449
449
|
fork,
|
|
450
450
|
parentBlockRoot,
|
|
451
|
+
currentState.latestExecutionPayloadHeader.blockHash,
|
|
451
452
|
safeBlockHash,
|
|
452
453
|
finalizedBlockHash ?? ZERO_HASH_HEX,
|
|
453
454
|
currentState,
|
|
@@ -613,17 +614,17 @@ export async function prepareExecutionPayload(
|
|
|
613
614
|
logger: Logger,
|
|
614
615
|
fork: ForkPostBellatrix,
|
|
615
616
|
parentBlockRoot: Root,
|
|
617
|
+
parentBlockHash: Bytes32,
|
|
616
618
|
safeBlockHash: RootHex,
|
|
617
619
|
finalizedBlockHash: RootHex,
|
|
618
620
|
state: IBeaconStateViewBellatrix,
|
|
619
621
|
suggestedFeeRecipient: string
|
|
620
622
|
): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
|
|
621
|
-
const parentHash = state.latestBlockHash;
|
|
622
623
|
const timestamp = computeTimeAtSlot(chain.config, state.slot, state.genesisTime);
|
|
623
624
|
const prevRandao = state.getRandaoMix(state.epoch);
|
|
624
625
|
|
|
625
626
|
const payloadIdCached = chain.executionEngine.payloadIdCache.get({
|
|
626
|
-
headBlockHash: toRootHex(
|
|
627
|
+
headBlockHash: toRootHex(parentBlockHash),
|
|
627
628
|
finalizedBlockHash,
|
|
628
629
|
timestamp: numToQuantity(timestamp),
|
|
629
630
|
prevRandao: toHex(prevRandao),
|
|
@@ -652,12 +653,13 @@ export async function prepareExecutionPayload(
|
|
|
652
653
|
prepareState: state,
|
|
653
654
|
prepareSlot: state.slot,
|
|
654
655
|
parentBlockRoot,
|
|
656
|
+
parentBlockHash,
|
|
655
657
|
feeRecipient: suggestedFeeRecipient,
|
|
656
658
|
});
|
|
657
659
|
|
|
658
660
|
payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
|
|
659
661
|
fork,
|
|
660
|
-
toRootHex(
|
|
662
|
+
toRootHex(parentBlockHash),
|
|
661
663
|
safeBlockHash,
|
|
662
664
|
finalizedBlockHash,
|
|
663
665
|
attributes
|
|
@@ -709,20 +711,30 @@ export function getPayloadAttributesForSSE(
|
|
|
709
711
|
prepareState,
|
|
710
712
|
prepareSlot,
|
|
711
713
|
parentBlockRoot,
|
|
714
|
+
parentBlockHash,
|
|
712
715
|
feeRecipient,
|
|
713
|
-
}: {
|
|
716
|
+
}: {
|
|
717
|
+
prepareState: IBeaconStateViewBellatrix;
|
|
718
|
+
prepareSlot: Slot;
|
|
719
|
+
parentBlockRoot: Root;
|
|
720
|
+
parentBlockHash: Bytes32;
|
|
721
|
+
feeRecipient: string;
|
|
722
|
+
}
|
|
714
723
|
): SSEPayloadAttributes {
|
|
715
|
-
const parentHash = prepareState.latestBlockHash;
|
|
716
724
|
const payloadAttributes = preparePayloadAttributes(fork, chain, {
|
|
717
725
|
prepareState,
|
|
718
726
|
prepareSlot,
|
|
719
727
|
parentBlockRoot,
|
|
728
|
+
parentBlockHash,
|
|
720
729
|
feeRecipient,
|
|
721
730
|
});
|
|
722
731
|
|
|
723
732
|
let parentBlockNumber: number;
|
|
724
733
|
if (isForkPostGloas(fork)) {
|
|
725
|
-
const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
|
|
734
|
+
const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
|
|
735
|
+
toRootHex(parentBlockRoot),
|
|
736
|
+
toRootHex(parentBlockHash)
|
|
737
|
+
);
|
|
726
738
|
if (parentBlock?.executionPayloadBlockHash == null) {
|
|
727
739
|
throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
|
|
728
740
|
}
|
|
@@ -736,7 +748,7 @@ export function getPayloadAttributesForSSE(
|
|
|
736
748
|
proposalSlot: prepareSlot,
|
|
737
749
|
parentBlockNumber,
|
|
738
750
|
parentBlockRoot,
|
|
739
|
-
parentBlockHash
|
|
751
|
+
parentBlockHash,
|
|
740
752
|
payloadAttributes,
|
|
741
753
|
};
|
|
742
754
|
return ssePayloadAttributes;
|
|
@@ -751,11 +763,13 @@ function preparePayloadAttributes(
|
|
|
751
763
|
prepareState,
|
|
752
764
|
prepareSlot,
|
|
753
765
|
parentBlockRoot,
|
|
766
|
+
parentBlockHash,
|
|
754
767
|
feeRecipient,
|
|
755
768
|
}: {
|
|
756
769
|
prepareState: IBeaconStateViewBellatrix;
|
|
757
770
|
prepareSlot: Slot;
|
|
758
771
|
parentBlockRoot: Root;
|
|
772
|
+
parentBlockHash: Bytes32;
|
|
759
773
|
feeRecipient: string;
|
|
760
774
|
}
|
|
761
775
|
): SSEPayloadAttributes["payloadAttributes"] {
|
|
@@ -772,13 +786,15 @@ function preparePayloadAttributes(
|
|
|
772
786
|
throw new Error("Expected Capella state for withdrawals");
|
|
773
787
|
}
|
|
774
788
|
|
|
775
|
-
if (isStatePostGloas(prepareState)
|
|
789
|
+
if (isStatePostGloas(prepareState)) {
|
|
790
|
+
const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
|
|
776
791
|
// When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
|
|
777
792
|
// already deducted from CL balances but never credited on the EL (the envelope
|
|
778
793
|
// was not delivered). The next payload must carry those same withdrawals to
|
|
779
794
|
// restore CL/EL consistency, otherwise validators permanently lose that balance.
|
|
780
|
-
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
781
|
-
prepareState.
|
|
795
|
+
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals = isExtendingPayload
|
|
796
|
+
? prepareState.getExpectedWithdrawals().expectedWithdrawals
|
|
797
|
+
: prepareState.payloadExpectedWithdrawals;
|
|
782
798
|
} else {
|
|
783
799
|
// withdrawals logic is now fork aware as it changes on electra fork post capella
|
|
784
800
|
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
@@ -790,6 +806,10 @@ function preparePayloadAttributes(
|
|
|
790
806
|
(payloadAttributes as deneb.SSEPayloadAttributes["payloadAttributes"]).parentBeaconBlockRoot = parentBlockRoot;
|
|
791
807
|
}
|
|
792
808
|
|
|
809
|
+
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
810
|
+
(payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
|
|
811
|
+
}
|
|
812
|
+
|
|
793
813
|
return payloadAttributes;
|
|
794
814
|
}
|
|
795
815
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {PayloadStatus} from "@lodestar/fork-choice";
|
|
2
1
|
import {Root, RootHex, Slot} from "@lodestar/types";
|
|
3
2
|
|
|
4
3
|
export enum RegenErrorCode {
|
|
@@ -10,8 +9,6 @@ export enum RegenErrorCode {
|
|
|
10
9
|
BLOCK_NOT_IN_DB = "REGEN_ERROR_BLOCK_NOT_IN_DB",
|
|
11
10
|
STATE_TRANSITION_ERROR = "REGEN_ERROR_STATE_TRANSITION_ERROR",
|
|
12
11
|
INVALID_STATE_ROOT = "REGEN_ERROR_INVALID_STATE_ROOT",
|
|
13
|
-
UNEXPECTED_PAYLOAD_STATUS = "REGEN_ERROR_UNEXPECTED_PAYLOAD_STATUS",
|
|
14
|
-
INTERNAL_ERROR = "REGEN_ERROR_INTERNAL_ERROR",
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
export type RegenErrorType =
|
|
@@ -22,9 +19,7 @@ export type RegenErrorType =
|
|
|
22
19
|
| {code: RegenErrorCode.TOO_MANY_BLOCK_PROCESSED; stateRoot: RootHex | Root}
|
|
23
20
|
| {code: RegenErrorCode.BLOCK_NOT_IN_DB; blockRoot: RootHex | Root}
|
|
24
21
|
| {code: RegenErrorCode.STATE_TRANSITION_ERROR; error: Error}
|
|
25
|
-
| {code: RegenErrorCode.INVALID_STATE_ROOT; slot: Slot; expected: RootHex; actual: RootHex}
|
|
26
|
-
| {code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS; blockRoot: RootHex | Root; payloadStatus: PayloadStatus}
|
|
27
|
-
| {code: RegenErrorCode.INTERNAL_ERROR; message: string};
|
|
22
|
+
| {code: RegenErrorCode.INVALID_STATE_ROOT; slot: Slot; expected: RootHex; actual: RootHex};
|
|
28
23
|
|
|
29
24
|
export class RegenError extends Error {
|
|
30
25
|
type: RegenErrorType;
|
|
@@ -2,7 +2,7 @@ import {routes} from "@lodestar/api";
|
|
|
2
2
|
import {ProtoBlock} from "@lodestar/fork-choice";
|
|
3
3
|
import {IBeaconStateView} from "@lodestar/state-transition";
|
|
4
4
|
import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
|
|
5
|
-
import {
|
|
5
|
+
import {CheckpointHex} from "../stateCache/types.js";
|
|
6
6
|
|
|
7
7
|
export enum RegenCaller {
|
|
8
8
|
getDuties = "getDuties",
|
|
@@ -40,20 +40,15 @@ export interface IStateRegenerator extends IStateRegeneratorInternal {
|
|
|
40
40
|
dumpCacheSummary(): routes.lodestar.StateCacheItem[];
|
|
41
41
|
getStateSync(stateRoot: RootHex): IBeaconStateView | null;
|
|
42
42
|
getPreStateSync(block: BeaconBlock): IBeaconStateView | null;
|
|
43
|
-
getCheckpointStateOrBytes(cp:
|
|
44
|
-
getCheckpointStateSync(cp:
|
|
43
|
+
getCheckpointStateOrBytes(cp: CheckpointHex): Promise<IBeaconStateView | Uint8Array | null>;
|
|
44
|
+
getCheckpointStateSync(cp: CheckpointHex): IBeaconStateView | null;
|
|
45
45
|
getClosestHeadState(head: ProtoBlock): IBeaconStateView | null;
|
|
46
46
|
pruneOnCheckpoint(finalizedEpoch: Epoch, justifiedEpoch: Epoch, headStateRoot: RootHex): void;
|
|
47
47
|
pruneOnFinalized(finalizedEpoch: Epoch): void;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* payloadPresent is true if this is payload state, false if block state.
|
|
52
|
-
* payloadPresent is always true for pre-gloas.
|
|
53
|
-
*/
|
|
54
|
-
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView, payloadPresent: boolean): void;
|
|
48
|
+
processState(blockRootHex: RootHex, postState: IBeaconStateView): void;
|
|
49
|
+
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView): void;
|
|
55
50
|
updateHeadState(newHead: ProtoBlock, maybeHeadState: IBeaconStateView): void;
|
|
56
|
-
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch
|
|
51
|
+
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null;
|
|
57
52
|
}
|
|
58
53
|
|
|
59
54
|
/**
|
|
@@ -5,7 +5,7 @@ import {BeaconBlock, Epoch, RootHex, Slot, isGloasBeaconBlock, phase0} from "@lo
|
|
|
5
5
|
import {Logger, toRootHex} from "@lodestar/utils";
|
|
6
6
|
import {Metrics} from "../../metrics/index.js";
|
|
7
7
|
import {JobItemQueue} from "../../util/queue/index.js";
|
|
8
|
-
import {BlockStateCache,
|
|
8
|
+
import {BlockStateCache, CheckpointHex, CheckpointStateCache} from "../stateCache/types.js";
|
|
9
9
|
import {RegenError, RegenErrorCode} from "./errors.js";
|
|
10
10
|
import {
|
|
11
11
|
IStateRegenerator,
|
|
@@ -125,14 +125,14 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
125
125
|
return null;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
async getCheckpointStateOrBytes(cp:
|
|
128
|
+
async getCheckpointStateOrBytes(cp: CheckpointHex): Promise<IBeaconStateView | Uint8Array | null> {
|
|
129
129
|
return this.checkpointStateCache.getStateOrBytes(cp);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
133
|
* Get checkpoint state from cache
|
|
134
134
|
*/
|
|
135
|
-
getCheckpointStateSync(cp:
|
|
135
|
+
getCheckpointStateSync(cp: CheckpointHex): IBeaconStateView | null {
|
|
136
136
|
return this.checkpointStateCache.get(cp);
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -153,22 +153,14 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
153
153
|
this.blockStateCache.deleteAllBeforeEpoch(finalizedEpoch);
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
processState(blockRootHex: RootHex, postState: IBeaconStateView): void {
|
|
157
157
|
this.blockStateCache.add(postState);
|
|
158
158
|
this.checkpointStateCache.processState(blockRootHex, postState).catch((e) => {
|
|
159
159
|
this.logger.debug("Error processing block state", {blockRootHex, slot: postState.slot}, e);
|
|
160
160
|
});
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
* Process payload state for caching after importing execution payload.
|
|
165
|
-
*/
|
|
166
|
-
processPayloadState(payloadState: IBeaconStateView): void {
|
|
167
|
-
// Add payload state to block state cache (keyed by payload state root)
|
|
168
|
-
this.blockStateCache.add(payloadState);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView, _payloadPresent: boolean): void {
|
|
163
|
+
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView): void {
|
|
172
164
|
this.checkpointStateCache.add(cp, item);
|
|
173
165
|
}
|
|
174
166
|
|
|
@@ -205,7 +197,7 @@ export class QueuedStateRegenerator implements IStateRegenerator {
|
|
|
205
197
|
}
|
|
206
198
|
}
|
|
207
199
|
|
|
208
|
-
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch
|
|
200
|
+
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null {
|
|
209
201
|
return this.checkpointStateCache.updatePreComputedCheckpoint(rootHex, epoch);
|
|
210
202
|
}
|
|
211
203
|
|
package/src/chain/regen/regen.ts
CHANGED
|
@@ -332,11 +332,6 @@ async function processSlotsByCheckpoint(
|
|
|
332
332
|
* emitting "checkpoint" events after every epoch processed.
|
|
333
333
|
*
|
|
334
334
|
* Stops processing after no more full epochs can be processed.
|
|
335
|
-
*
|
|
336
|
-
* Output state variant:
|
|
337
|
-
* - Post-Gloas: If slots are processed, returns block state (payloadPresent=false).
|
|
338
|
-
* If no slots processed, returns preState as-is (preserves variant).
|
|
339
|
-
* - Pre-Gloas: Always payloadPresent=true (no block/payload distinction).
|
|
340
335
|
*/
|
|
341
336
|
export async function processSlotsToNearestCheckpoint(
|
|
342
337
|
modules: {
|
|
@@ -380,9 +375,6 @@ export async function processSlotsToNearestCheckpoint(
|
|
|
380
375
|
// This may becomes the "official" checkpoint state if the 1st block of epoch is skipped
|
|
381
376
|
const checkpointState = postState;
|
|
382
377
|
const cp = getCheckpointFromState(checkpointState);
|
|
383
|
-
// processSlots() only does epoch transitions, never processes payloads
|
|
384
|
-
// Pre-Gloas: payloadPresent is always true (execution payload embedded in block)
|
|
385
|
-
// Post-Gloas: result is a block state (payloadPresent=false)
|
|
386
378
|
checkpointStateCache.add(cp, checkpointState);
|
|
387
379
|
// consumers should not mutate state ever
|
|
388
380
|
emitter?.emit(ChainEvent.checkpoint, cp, checkpointState);
|
|
@@ -9,7 +9,7 @@ import {IClock} from "../../util/clock.js";
|
|
|
9
9
|
import {serializeState} from "../serializeState.js";
|
|
10
10
|
import {CPStateDatastore, DatastoreKey} from "./datastore/index.js";
|
|
11
11
|
import {MapTracker} from "./mapMetrics.js";
|
|
12
|
-
import {BlockStateCache, CacheItemType, CheckpointHex,
|
|
12
|
+
import {BlockStateCache, CacheItemType, CheckpointHex, CheckpointStateCache} from "./types.js";
|
|
13
13
|
|
|
14
14
|
export type PersistentCheckpointStateCacheOpts = {
|
|
15
15
|
/** Keep max n state epochs in memory, persist the rest to disk */
|
|
@@ -226,7 +226,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
226
226
|
}
|
|
227
227
|
sszTimer?.();
|
|
228
228
|
const timer = this.metrics?.cpStateCache.stateReloadDuration.startTimer();
|
|
229
|
-
|
|
229
|
+
// preload validators and balances for faster state transition
|
|
230
|
+
const newCachedState = seedState.loadOtherState(stateBytes, validatorsBytes, {
|
|
231
|
+
preloadValidatorsAndBalances: true,
|
|
232
|
+
});
|
|
230
233
|
// hashTreeRoot() calls the commit() inside
|
|
231
234
|
// there is no modification inside the state, it's just that we want to compute and cache all roots
|
|
232
235
|
const stateRoot = toRootHex(newCachedState.hashTreeRoot());
|
|
@@ -843,19 +846,6 @@ export function toCheckpointHex(checkpoint: phase0.Checkpoint): CheckpointHex {
|
|
|
843
846
|
};
|
|
844
847
|
}
|
|
845
848
|
|
|
846
|
-
/** TODO GLOAS: remove after rolling back regen dual-state changes */
|
|
847
|
-
export function fcCheckpointToHexPayload(checkpoint: {
|
|
848
|
-
epoch: Epoch;
|
|
849
|
-
rootHex: RootHex;
|
|
850
|
-
payloadStatus?: number;
|
|
851
|
-
}): CheckpointHexPayload {
|
|
852
|
-
return {
|
|
853
|
-
epoch: checkpoint.epoch,
|
|
854
|
-
rootHex: checkpoint.rootHex,
|
|
855
|
-
payloadPresent: true,
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
|
|
859
849
|
export function toCheckpointKey(cp: CheckpointHex): string {
|
|
860
850
|
return `${cp.rootHex}:${cp.epoch}`;
|
|
861
851
|
}
|
|
@@ -4,9 +4,6 @@ import {Epoch, RootHex, phase0} from "@lodestar/types";
|
|
|
4
4
|
|
|
5
5
|
export type CheckpointHex = {epoch: Epoch; rootHex: RootHex};
|
|
6
6
|
|
|
7
|
-
/** TODO GLOAS: payloadPresent is ignored — remove after rolling back regen dual-state changes */
|
|
8
|
-
export type CheckpointHexPayload = {epoch: Epoch; rootHex: RootHex; payloadPresent: boolean};
|
|
9
|
-
|
|
10
7
|
/**
|
|
11
8
|
* Lodestar currently keeps two state caches around.
|
|
12
9
|
*
|
|
@@ -90,6 +90,19 @@ async function validateAggregateAndProof(
|
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
// [REJECT] If `aggregate.data.index == 1` (payload present for a past
|
|
94
|
+
// block), the execution payload for `block` passes validation.
|
|
95
|
+
// [IGNORE] When `aggregate.data.index == 1` (payload present for a past block),
|
|
96
|
+
// the corresponding execution payload for `block` has been seen (a client MAY queue
|
|
97
|
+
// attestations for processing once the payload is retrieved and SHOULD request the
|
|
98
|
+
// payload envelope via `ExecutionPayloadEnvelopesByRoot`).
|
|
99
|
+
if (block !== null && attData.index === 1 && !chain.seenPayloadEnvelope(toRootHex(attData.beaconBlockRoot))) {
|
|
100
|
+
throw new AttestationError(GossipAction.IGNORE, {
|
|
101
|
+
code: AttestationErrorCode.EXECUTION_PAYLOAD_NOT_SEEN,
|
|
102
|
+
beaconBlockRoot: toRootHex(attData.beaconBlockRoot),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
93
106
|
// [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(aggregate)
|
|
94
107
|
committeeIndex = (aggregate as electra.Attestation).committeeBits.getSingleTrueBit();
|
|
95
108
|
if (committeeIndex === null) {
|
|
@@ -315,6 +315,19 @@ async function validateAttestationNoSignatureCheck(
|
|
|
315
315
|
code: AttestationErrorCode.PREMATURELY_INDICATED_PAYLOAD_PRESENT,
|
|
316
316
|
});
|
|
317
317
|
}
|
|
318
|
+
|
|
319
|
+
// [REJECT] If `attestation.data.index == 1` (payload present for a past
|
|
320
|
+
// block), the execution payload for `block` passes validation.
|
|
321
|
+
// [IGNORE] When `attestation.data.index == 1` (payload present for a past block),
|
|
322
|
+
// the corresponding execution payload for `block` has been seen (a client MAY queue
|
|
323
|
+
// attestations for processing once the payload is retrieved and SHOULD request the
|
|
324
|
+
// payload envelope via `ExecutionPayloadEnvelopesByRoot`).
|
|
325
|
+
if (block !== null && attData.index === 1 && !chain.seenPayloadEnvelope(toRootHex(attData.beaconBlockRoot))) {
|
|
326
|
+
throw new AttestationError(GossipAction.IGNORE, {
|
|
327
|
+
code: AttestationErrorCode.EXECUTION_PAYLOAD_NOT_SEEN,
|
|
328
|
+
beaconBlockRoot: toRootHex(attData.beaconBlockRoot),
|
|
329
|
+
});
|
|
330
|
+
}
|
|
318
331
|
} else {
|
|
319
332
|
// [REJECT] attestation.data.index == 0
|
|
320
333
|
if (attData.index !== 0) {
|