@lodestar/beacon-node 1.50.0-dev.08c4bed201 → 1.50.0-dev.09bef4706f
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 +7 -2
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +57 -17
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/ColumnReconstructionTracker.d.ts +0 -2
- package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
- package/lib/chain/ColumnReconstructionTracker.js +4 -5
- package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
- package/lib/chain/beaconProposerCache.d.ts +6 -0
- package/lib/chain/beaconProposerCache.d.ts.map +1 -1
- package/lib/chain/beaconProposerCache.js +16 -0
- package/lib/chain/beaconProposerCache.js.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.d.ts +1 -1
- package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +8 -6
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/chain.d.ts +1 -0
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +16 -2
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/interface.d.ts +3 -1
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +15 -6
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +8 -0
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +48 -34
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/reprocess.d.ts +2 -1
- package/lib/chain/reprocess.d.ts.map +1 -1
- package/lib/chain/reprocess.js +2 -1
- package/lib/chain/reprocess.js.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.js +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +6 -4
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/constants/constants.d.ts +1 -0
- package/lib/constants/constants.d.ts.map +1 -1
- package/lib/constants/constants.js +1 -0
- package/lib/constants/constants.js.map +1 -1
- package/lib/db/repositories/blockArchive.js +2 -2
- package/lib/db/repositories/blockArchive.js.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.d.ts +1 -1
- package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.js +1 -2
- package/lib/db/repositories/blockArchiveIndex.js.map +1 -1
- package/lib/execution/engine/blobVersionedHashes.d.ts +9 -0
- package/lib/execution/engine/blobVersionedHashes.d.ts.map +1 -0
- package/lib/execution/engine/blobVersionedHashes.js +74 -0
- package/lib/execution/engine/blobVersionedHashes.js.map +1 -0
- package/lib/execution/engine/http.d.ts +45 -13
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +236 -198
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/index.d.ts +3 -2
- package/lib/execution/engine/index.d.ts.map +1 -1
- package/lib/execution/engine/index.js +33 -8
- package/lib/execution/engine/index.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +1 -1
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/jsonRpcHttpClient.d.ts.map +1 -1
- package/lib/execution/engine/jsonRpcHttpClient.js +14 -4
- package/lib/execution/engine/jsonRpcHttpClient.js.map +1 -1
- package/lib/execution/engine/jsonRpcTransport.d.ts +25 -0
- package/lib/execution/engine/jsonRpcTransport.d.ts.map +1 -0
- package/lib/execution/engine/jsonRpcTransport.js +158 -0
- package/lib/execution/engine/jsonRpcTransport.js.map +1 -0
- package/lib/execution/engine/restHttpClient.d.ts +71 -0
- package/lib/execution/engine/restHttpClient.d.ts.map +1 -0
- package/lib/execution/engine/restHttpClient.js +201 -0
- package/lib/execution/engine/restHttpClient.js.map +1 -0
- package/lib/execution/engine/restTransport.d.ts +48 -0
- package/lib/execution/engine/restTransport.d.ts.map +1 -0
- package/lib/execution/engine/restTransport.js +411 -0
- package/lib/execution/engine/restTransport.js.map +1 -0
- package/lib/execution/engine/sszTypes.d.ts +1261 -0
- package/lib/execution/engine/sszTypes.d.ts.map +1 -0
- package/lib/execution/engine/sszTypes.js +216 -0
- package/lib/execution/engine/sszTypes.js.map +1 -0
- package/lib/execution/engine/transport.d.ts +39 -0
- package/lib/execution/engine/transport.d.ts.map +1 -0
- package/lib/execution/engine/transport.js +2 -0
- package/lib/execution/engine/transport.js.map +1 -0
- package/lib/execution/engine/transportMetrics.d.ts +5 -1
- package/lib/execution/engine/transportMetrics.d.ts.map +1 -1
- package/lib/execution/engine/types.d.ts +2 -0
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +31 -63
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/execution/engine/utils.d.ts.map +1 -1
- package/lib/execution/engine/utils.js +9 -2
- package/lib/execution/engine/utils.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +7 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +12 -1
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +0 -14
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +1 -1
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/index.js +3 -3
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/rateLimit.js +2 -2
- package/lib/network/reqresp/rateLimit.js.map +1 -1
- package/lib/network/subnets/attnetsService.d.ts.map +1 -1
- package/lib/network/subnets/attnetsService.js +3 -1
- package/lib/network/subnets/attnetsService.js.map +1 -1
- package/lib/node/notifier.d.ts.map +1 -1
- package/lib/node/notifier.js +12 -13
- package/lib/node/notifier.js.map +1 -1
- package/lib/node/options.d.ts +3 -2
- package/lib/node/options.d.ts.map +1 -1
- package/lib/node/options.js +2 -2
- package/lib/node/options.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +3 -2
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/clock.d.ts.map +1 -1
- package/lib/util/clock.js +3 -4
- package/lib/util/clock.js.map +1 -1
- package/lib/util/sszBytes.d.ts +2 -2
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +22 -14
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +16 -15
- package/src/api/impl/beacon/blocks/index.ts +10 -3
- package/src/api/impl/validator/index.ts +78 -19
- package/src/chain/ColumnReconstructionTracker.ts +4 -6
- package/src/chain/beaconProposerCache.ts +19 -1
- package/src/chain/blocks/blockInput/blockInput.ts +1 -1
- package/src/chain/blocks/importBlock.ts +9 -6
- package/src/chain/chain.ts +18 -2
- package/src/chain/interface.ts +4 -1
- package/src/chain/prepareNextSlot.ts +22 -6
- package/src/chain/produceBlock/computeNewStateRoot.ts +9 -2
- package/src/chain/produceBlock/produceBlockBody.ts +78 -39
- package/src/chain/reprocess.ts +2 -1
- package/src/chain/seenCache/seenGossipBlockInput.ts +2 -1
- package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
- package/src/chain/validatorMonitor.ts +7 -4
- package/src/constants/constants.ts +1 -0
- package/src/db/repositories/blockArchive.ts +2 -2
- package/src/db/repositories/blockArchiveIndex.ts +2 -3
- package/src/execution/engine/blobVersionedHashes.ts +72 -0
- package/src/execution/engine/http.ts +304 -271
- package/src/execution/engine/index.ts +42 -7
- package/src/execution/engine/interface.ts +1 -1
- package/src/execution/engine/jsonRpcHttpClient.ts +12 -5
- package/src/execution/engine/jsonRpcTransport.ts +247 -0
- package/src/execution/engine/restHttpClient.ts +269 -0
- package/src/execution/engine/restTransport.ts +575 -0
- package/src/execution/engine/sszTypes.ts +354 -0
- package/src/execution/engine/transport.ts +61 -0
- package/src/execution/engine/transportMetrics.ts +2 -1
- package/src/execution/engine/types.ts +42 -80
- package/src/execution/engine/utils.ts +12 -2
- package/src/metrics/metrics/lodestar.ts +12 -1
- package/src/network/processor/gossipHandlers.ts +1 -1
- package/src/network/processor/index.ts +3 -3
- package/src/network/reqresp/rateLimit.ts +2 -2
- package/src/network/subnets/attnetsService.ts +8 -3
- package/src/node/notifier.ts +14 -13
- package/src/node/options.ts +10 -1
- package/src/sync/unknownBlock.ts +3 -2
- package/src/util/clock.ts +3 -4
- package/src/util/sszBytes.ts +25 -12
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
isStatePostGloas,
|
|
23
23
|
} from "@lodestar/state-transition";
|
|
24
24
|
import {Bytes32, Slot, ValidatorIndex} from "@lodestar/types";
|
|
25
|
-
import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils";
|
|
25
|
+
import {Logger, fromHex, isErrorAborted, sleep, toHex} from "@lodestar/utils";
|
|
26
26
|
import {GENESIS_SLOT} from "../constants/constants.js";
|
|
27
27
|
import {BuilderStatus} from "../execution/builder/http.js";
|
|
28
28
|
import {PayloadAttributes} from "../execution/index.js";
|
|
@@ -31,7 +31,11 @@ import {ClockEvent} from "../util/clock.js";
|
|
|
31
31
|
import {isQueueErrorAborted} from "../util/queue/index.js";
|
|
32
32
|
import {ForkchoiceCaller} from "./forkChoice/index.js";
|
|
33
33
|
import {IBeaconChain} from "./interface.js";
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
getPayloadAttributesForSSE,
|
|
36
|
+
getPooledProposerPreferences,
|
|
37
|
+
prepareExecutionPayload,
|
|
38
|
+
} from "./produceBlock/produceBlockBody.js";
|
|
35
39
|
import {RegenCaller} from "./regen/index.js";
|
|
36
40
|
|
|
37
41
|
// TODO GLOAS: re-evaluate this timing
|
|
@@ -92,6 +96,7 @@ export class PrepareNextSlotScheduler {
|
|
|
92
96
|
const nextEpoch = computeEpochAtSlot(clockSlot) + 1;
|
|
93
97
|
const isEpochTransition = prepareEpoch === nextEpoch;
|
|
94
98
|
const fork = this.config.getForkName(prepareSlot);
|
|
99
|
+
const currentFork = this.config.getForkName(clockSlot);
|
|
95
100
|
|
|
96
101
|
// Early return if we are pre-genesis
|
|
97
102
|
// or we are pre-bellatrix and this is not an epoch transition
|
|
@@ -102,7 +107,7 @@ export class PrepareNextSlotScheduler {
|
|
|
102
107
|
try {
|
|
103
108
|
// At PREPARE_NEXT_SLOT_BPS (~67%) of the current slot we prepare payload for the next slot
|
|
104
109
|
// or precompute epoch transition
|
|
105
|
-
await sleep(this.config.getSlotComponentDurationMs(PREPARE_NEXT_SLOT_BPS), this.signal);
|
|
110
|
+
await sleep(this.config.getSlotComponentDurationMs(currentFork, PREPARE_NEXT_SLOT_BPS), this.signal);
|
|
106
111
|
|
|
107
112
|
// calling updateHead() here before we produce a block to reduce reorg possibility
|
|
108
113
|
const headBlock = this.chain.recomputeForkChoiceHead(ForkchoiceCaller.prepareNextSlot);
|
|
@@ -158,7 +163,15 @@ export class PrepareNextSlotScheduler {
|
|
|
158
163
|
};
|
|
159
164
|
|
|
160
165
|
const proposerIndex = await getProposerIndex();
|
|
161
|
-
|
|
166
|
+
if (this.chain.beaconProposerCache.has(proposerIndex)) {
|
|
167
|
+
const pooledPreferences = isForkPostGloas(fork)
|
|
168
|
+
? getPooledProposerPreferences(this.chain, prepareSlot, headRoot)
|
|
169
|
+
: null;
|
|
170
|
+
feeRecipient =
|
|
171
|
+
pooledPreferences !== null
|
|
172
|
+
? toHex(pooledPreferences.feeRecipient)
|
|
173
|
+
: this.chain.beaconProposerCache.getOrDefault(proposerIndex);
|
|
174
|
+
}
|
|
162
175
|
|
|
163
176
|
// Predict the proposer head of the next slot when either:
|
|
164
177
|
// - we are proposing the next slot (single-slot proposer-boost-reorg), or
|
|
@@ -357,7 +370,7 @@ export class PrepareNextSlotScheduler {
|
|
|
357
370
|
// skip when we're the next-slot proposer — don't compete with block-production prep.
|
|
358
371
|
feeRecipient === undefined
|
|
359
372
|
) {
|
|
360
|
-
const maxDurationMs = this.config.getSlotComponentDurationMs(BUILDER_PREVERIFY_LIMIT_BPS);
|
|
373
|
+
const maxDurationMs = this.config.getSlotComponentDurationMs(currentFork, BUILDER_PREVERIFY_LIMIT_BPS);
|
|
361
374
|
const preVerifyTimer = this.metrics?.builderDepositPreVerify.duration.startTimer();
|
|
362
375
|
const result = headState.preVerifyBuilderDepositsPreGloas(MAX_BUILDER_DEPOSITS_PER_SLOT, maxDurationMs);
|
|
363
376
|
preVerifyTimer?.();
|
|
@@ -411,7 +424,10 @@ export class PrepareNextSlotScheduler {
|
|
|
411
424
|
* later in the slot, connecting at PREPARE_NEXT_SLOT_BPS would go cold before bids are requested.
|
|
412
425
|
*/
|
|
413
426
|
private checkBuilderStatusBeforeSlot(prepareSlot: Slot): void {
|
|
414
|
-
const msBeforeSlot = this.config.getSlotComponentDurationMs(
|
|
427
|
+
const msBeforeSlot = this.config.getSlotComponentDurationMs(
|
|
428
|
+
this.config.getForkName(prepareSlot - 1),
|
|
429
|
+
BUILDER_STATUS_CHECK_BEFORE_SLOT_BPS
|
|
430
|
+
);
|
|
415
431
|
const msUntilCheck = -this.chain.clock.msFromSlot(prepareSlot) - msBeforeSlot;
|
|
416
432
|
sleep(Math.max(0, msUntilCheck), this.signal)
|
|
417
433
|
.then(() => this.chain.builderApiClient.checkStatus())
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import {EMPTY_SIGNATURE, IBeaconStateView, StateHashTreeRootSource} from "@lodestar/state-transition";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
BeaconBlock,
|
|
4
|
+
BlindedBeaconBlock,
|
|
5
|
+
Gwei,
|
|
6
|
+
Root,
|
|
7
|
+
SignedBeaconBlock,
|
|
8
|
+
SignedBlindedBeaconBlock,
|
|
9
|
+
} from "@lodestar/types";
|
|
3
10
|
import {Metrics} from "../../metrics/index.js";
|
|
4
11
|
|
|
5
12
|
/**
|
|
@@ -13,7 +20,7 @@ export function computeNewStateRoot(
|
|
|
13
20
|
block: BeaconBlock | BlindedBeaconBlock
|
|
14
21
|
): {newStateRoot: Root; proposerReward: Gwei; postState: IBeaconStateView} {
|
|
15
22
|
// Set signature to zero to re-use stateTransition() function which requires the SignedBeaconBlock type
|
|
16
|
-
const signedBlock = {message: block, signature: EMPTY_SIGNATURE};
|
|
23
|
+
const signedBlock = {message: block, signature: EMPTY_SIGNATURE} as SignedBeaconBlock | SignedBlindedBeaconBlock;
|
|
17
24
|
const {newStateRoot, proposerReward, postState, hashTreeRootTime} = state.computeNewStateRoot(
|
|
18
25
|
{block: signedBlock},
|
|
19
26
|
{metrics: metrics?.stateTransition}
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
isForkPostAltair,
|
|
21
21
|
isForkPostBellatrix,
|
|
22
22
|
isForkPostGloas,
|
|
23
|
+
isForkPostHeze,
|
|
23
24
|
} from "@lodestar/params";
|
|
24
25
|
import {
|
|
25
26
|
G2_POINT_AT_INFINITY,
|
|
@@ -77,6 +78,7 @@ import {IExecutionBuilder, IExecutionEngine, PayloadAttributes, PayloadId} from
|
|
|
77
78
|
import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
|
|
78
79
|
import {fromGraffitiBytes} from "../../util/graffiti.js";
|
|
79
80
|
import {kzg} from "../../util/kzg.js";
|
|
81
|
+
import {BeaconProposerCache} from "../beaconProposerCache.js";
|
|
80
82
|
import type {BeaconChain} from "../chain.js";
|
|
81
83
|
import {CommonBlockBody} from "../interface.js";
|
|
82
84
|
import {ProposerPreferencesPool} from "../opPools/index.js";
|
|
@@ -286,10 +288,13 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
286
288
|
// this into a completely separate function and have pre/post gloas more separated
|
|
287
289
|
const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice, this.logger);
|
|
288
290
|
const finalizedBlockHash = getFinalizedExecutionBlockHash(this.forkChoice);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
291
|
+
const {feeRecipient, feeRecipientType} = getProposerFeeRecipient(
|
|
292
|
+
requestedFeeRecipient,
|
|
293
|
+
getPooledProposerPreferences(this, blockSlot, parentBlock.blockRoot),
|
|
294
|
+
this.beaconProposerCache,
|
|
295
|
+
proposerIndex
|
|
296
|
+
);
|
|
297
|
+
Object.assign(logMeta, {feeRecipientType, feeRecipient});
|
|
293
298
|
|
|
294
299
|
const endExecutionPayload = this.metrics?.executionBlockProductionTimeSteps.startTimer();
|
|
295
300
|
|
|
@@ -442,13 +447,12 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
442
447
|
|
|
443
448
|
const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice, this.logger);
|
|
444
449
|
const finalizedBlockHash = getFinalizedExecutionBlockHash(this.forkChoice);
|
|
445
|
-
const feeRecipient =
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
450
|
+
const {feeRecipient, feeRecipientType} = getProposerFeeRecipient(
|
|
451
|
+
requestedFeeRecipient,
|
|
452
|
+
null,
|
|
453
|
+
this.beaconProposerCache,
|
|
454
|
+
proposerIndex
|
|
455
|
+
);
|
|
452
456
|
Object.assign(logMeta, {feeRecipientType, feeRecipient});
|
|
453
457
|
|
|
454
458
|
if (blockType === BlockType.Blinded) {
|
|
@@ -681,12 +685,11 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
681
685
|
executionPayloadValue = BigInt(0);
|
|
682
686
|
}
|
|
683
687
|
|
|
684
|
-
const {graffiti, attestations,
|
|
688
|
+
const {graffiti, attestations, voluntaryExits, attesterSlashings, proposerSlashings} = blockBody;
|
|
685
689
|
|
|
686
690
|
Object.assign(logMeta, {
|
|
687
691
|
graffiti: fromGraffitiBytes(graffiti),
|
|
688
692
|
attestations: attestations.length,
|
|
689
|
-
deposits: deposits.length,
|
|
690
693
|
voluntaryExits: voluntaryExits.length,
|
|
691
694
|
attesterSlashings: attesterSlashings.length,
|
|
692
695
|
proposerSlashings: proposerSlashings.length,
|
|
@@ -974,9 +977,8 @@ function preparePayloadAttributes(
|
|
|
974
977
|
* Resolve the proposer's preferred (target) gas limit for the Gloas `PayloadAttributesV4`
|
|
975
978
|
* `targetGasLimit` field (consensus-specs#5235, execution-apis#796).
|
|
976
979
|
*
|
|
977
|
-
* Sourced from the `SignedProposerPreferences` the proposer's VC submitted to the pool
|
|
978
|
-
*
|
|
979
|
-
* preferences are pooled, target the parent payload's gas limit so the gas limit stays
|
|
980
|
+
* Sourced from the `SignedProposerPreferences` the proposer's VC submitted to the pool. When no
|
|
981
|
+
* matching preferences are pooled, target the parent payload's gas limit so the gas limit stays
|
|
980
982
|
* unchanged (`is_gas_limit_target_compatible` then requires `gas_limit == parent_gas_limit`).
|
|
981
983
|
*
|
|
982
984
|
* The parent payload's gas_limit is read from fork choice — the variant matching
|
|
@@ -991,26 +993,9 @@ function getProposerTargetGasLimit(
|
|
|
991
993
|
parentBlockHash: Bytes32
|
|
992
994
|
): bigint {
|
|
993
995
|
const parentBlockRootHex = toRootHex(parentBlockRoot);
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
return null;
|
|
998
|
-
}
|
|
999
|
-
try {
|
|
1000
|
-
return getShufflingDependentRoot(
|
|
1001
|
-
chain.forkChoice,
|
|
1002
|
-
computeEpochAtSlot(prepareSlot),
|
|
1003
|
-
computeEpochAtSlot(parentBlock.slot),
|
|
1004
|
-
parentBlock
|
|
1005
|
-
);
|
|
1006
|
-
} catch {
|
|
1007
|
-
return null;
|
|
1008
|
-
}
|
|
1009
|
-
})();
|
|
1010
|
-
|
|
1011
|
-
const pref = dependentRootHex !== null ? chain.proposerPreferencesPool.get(prepareSlot, dependentRootHex) : null;
|
|
1012
|
-
if (pref !== null) {
|
|
1013
|
-
return pref.message.targetGasLimit;
|
|
996
|
+
const preferences = getPooledProposerPreferences(chain, prepareSlot, parentBlockRootHex);
|
|
997
|
+
if (preferences !== null) {
|
|
998
|
+
return preferences.targetGasLimit;
|
|
1014
999
|
}
|
|
1015
1000
|
|
|
1016
1001
|
const parentPayloadVariant = chain.forkChoice.getBlockHexAndBlockHash(parentBlockRootHex, toRootHex(parentBlockHash));
|
|
@@ -1022,6 +1007,55 @@ function getProposerTargetGasLimit(
|
|
|
1022
1007
|
return BigInt(parentPayloadVariant.executionPayloadGasLimit);
|
|
1023
1008
|
}
|
|
1024
1009
|
|
|
1010
|
+
/** The proposer's request wins over its signed preferences, which win over its registered proposer data */
|
|
1011
|
+
function getProposerFeeRecipient(
|
|
1012
|
+
requestedFeeRecipient: string | undefined,
|
|
1013
|
+
pooledPreferences: gloas.ProposerPreferences | null,
|
|
1014
|
+
beaconProposerCache: BeaconProposerCache,
|
|
1015
|
+
proposerIndex: ValidatorIndex
|
|
1016
|
+
): {feeRecipient: string; feeRecipientType: "requested" | "preferences" | "cached" | "default"} {
|
|
1017
|
+
if (requestedFeeRecipient !== undefined) {
|
|
1018
|
+
return {feeRecipient: requestedFeeRecipient, feeRecipientType: "requested"};
|
|
1019
|
+
}
|
|
1020
|
+
if (pooledPreferences !== null) {
|
|
1021
|
+
return {feeRecipient: toHex(pooledPreferences.feeRecipient), feeRecipientType: "preferences"};
|
|
1022
|
+
}
|
|
1023
|
+
const cachedFeeRecipient = beaconProposerCache.get(proposerIndex);
|
|
1024
|
+
if (cachedFeeRecipient !== undefined) {
|
|
1025
|
+
return {feeRecipient: cachedFeeRecipient, feeRecipientType: "cached"};
|
|
1026
|
+
}
|
|
1027
|
+
return {feeRecipient: beaconProposerCache.getOrDefault(proposerIndex), feeRecipientType: "default"};
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* The preferences the proposer of `slot` signed for the branch of `parentBlockRoot`, the same
|
|
1032
|
+
* `(slot, dependent_root)` lookup as gossip bid validation. Null if none are pooled.
|
|
1033
|
+
*/
|
|
1034
|
+
export function getPooledProposerPreferences(
|
|
1035
|
+
chain: {forkChoice: IForkChoice; proposerPreferencesPool: ProposerPreferencesPool},
|
|
1036
|
+
slot: Slot,
|
|
1037
|
+
parentBlockRootHex: RootHex
|
|
1038
|
+
): gloas.ProposerPreferences | null {
|
|
1039
|
+
const parentBlock = chain.forkChoice.getBlockHexDefaultStatus(parentBlockRootHex);
|
|
1040
|
+
if (parentBlock === null) {
|
|
1041
|
+
return null;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
let dependentRootHex: RootHex;
|
|
1045
|
+
try {
|
|
1046
|
+
dependentRootHex = getShufflingDependentRoot(
|
|
1047
|
+
chain.forkChoice,
|
|
1048
|
+
computeEpochAtSlot(slot),
|
|
1049
|
+
computeEpochAtSlot(parentBlock.slot),
|
|
1050
|
+
parentBlock
|
|
1051
|
+
);
|
|
1052
|
+
} catch {
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
return chain.proposerPreferencesPool.get(slot, dependentRootHex)?.message ?? null;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1025
1059
|
export async function produceCommonBlockBody<T extends BlockType>(
|
|
1026
1060
|
this: BeaconChain,
|
|
1027
1061
|
blockType: T,
|
|
@@ -1072,16 +1106,21 @@ export async function produceCommonBlockBody<T extends BlockType>(
|
|
|
1072
1106
|
});
|
|
1073
1107
|
|
|
1074
1108
|
// Live proposal production is supported from Fulu onward.
|
|
1075
|
-
|
|
1109
|
+
const commonBlockBody: CommonBlockBody = {
|
|
1076
1110
|
randaoReveal,
|
|
1077
1111
|
graffiti,
|
|
1078
|
-
eth1Data: currentState.eth1Data,
|
|
1079
1112
|
proposerSlashings: this.opts.disableProposerSlashings === true ? [] : proposerSlashings,
|
|
1080
1113
|
attesterSlashings,
|
|
1081
1114
|
attestations,
|
|
1082
|
-
deposits: [],
|
|
1083
1115
|
voluntaryExits,
|
|
1084
1116
|
blsToExecutionChanges,
|
|
1085
1117
|
syncAggregate,
|
|
1086
1118
|
};
|
|
1119
|
+
|
|
1120
|
+
if (!isForkPostHeze(fork)) {
|
|
1121
|
+
commonBlockBody.eth1Data = currentState.eth1Data;
|
|
1122
|
+
commonBlockBody.deposits = [];
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
return commonBlockBody;
|
|
1087
1126
|
}
|
package/src/chain/reprocess.ts
CHANGED
|
@@ -5,8 +5,9 @@ import {Metrics} from "../metrics/index.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* To prevent our node from having to reprocess while struggling to sync,
|
|
7
7
|
* we only want to reprocess attestations if block reaches our node before this time.
|
|
8
|
+
* Expressed in basis points of slot duration (1667 BPS = 2s for 12s slots).
|
|
8
9
|
*/
|
|
9
|
-
export const
|
|
10
|
+
export const REPROCESS_MIN_TIME_TO_NEXT_SLOT_BPS = 1667;
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Reprocess status for metrics
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ForkName,
|
|
5
5
|
ForkPostFulu,
|
|
6
6
|
ForkPostGloas,
|
|
7
|
+
ForkPreDeneb,
|
|
7
8
|
ForkPreGloas,
|
|
8
9
|
SLOTS_PER_EPOCH,
|
|
9
10
|
isForkPostDeneb,
|
|
@@ -240,7 +241,7 @@ export class SeenBlockInput {
|
|
|
240
241
|
} else if (!isForkPostDeneb(forkName)) {
|
|
241
242
|
// Pre-deneb
|
|
242
243
|
blockInput = BlockInputPreData.createFromBlock({
|
|
243
|
-
block
|
|
244
|
+
block: block as SignedBeaconBlock<ForkPreDeneb>,
|
|
244
245
|
blockRootHex,
|
|
245
246
|
daOutOfRange,
|
|
246
247
|
forkName,
|
|
@@ -592,7 +592,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
592
592
|
}
|
|
593
593
|
|
|
594
594
|
const blockSlot = state.slot;
|
|
595
|
-
const processCPStatesTimeMs = this.config.getSlotComponentDurationMs(
|
|
595
|
+
const processCPStatesTimeMs = this.config.getSlotComponentDurationMs(
|
|
596
|
+
this.config.getForkName(blockSlot),
|
|
597
|
+
PROCESS_CHECKPOINT_STATES_BPS
|
|
598
|
+
);
|
|
596
599
|
// we always have clock in production, fallback value is only for test
|
|
597
600
|
const msFromSlot = this.clock?.msFromSlot(blockSlot) ?? processCPStatesTimeMs;
|
|
598
601
|
const msToProcessCPStates = processCPStatesTimeMs - msFromSlot;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
2
|
+
import {ForkName, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
3
3
|
import {
|
|
4
4
|
IBeaconStateView,
|
|
5
5
|
ParticipationFlags,
|
|
@@ -776,13 +776,14 @@ export function createValidatorMonitor(
|
|
|
776
776
|
|
|
777
777
|
if (isStatePostAltair(headState)) {
|
|
778
778
|
const prevEpochStartSlot = computeStartSlotAtEpoch(prevEpoch);
|
|
779
|
+
const prevEpochFork = config.getForkName(prevEpochStartSlot);
|
|
779
780
|
const prevEpochTargetRoot = toRootHex(headState.getBlockRootAtSlot(prevEpochStartSlot));
|
|
780
781
|
|
|
781
782
|
// Check attestation performance
|
|
782
783
|
for (const [index, validator] of validators.entries()) {
|
|
783
784
|
const flags = parseParticipationFlags(headState.getPreviousEpochParticipation(index));
|
|
784
785
|
const attestationSummary = validator.attestations.get(prevEpoch)?.get(prevEpochTargetRoot);
|
|
785
|
-
const summary = renderAttestationSummary(config, rootCache, attestationSummary, flags);
|
|
786
|
+
const summary = renderAttestationSummary(config, prevEpochFork, rootCache, attestationSummary, flags);
|
|
786
787
|
validatorMonitorMetrics?.prevEpochAttestationSummary.inc({summary});
|
|
787
788
|
log("Previous epoch attestation", {
|
|
788
789
|
validator: index,
|
|
@@ -941,6 +942,7 @@ export function createValidatorMonitor(
|
|
|
941
942
|
*/
|
|
942
943
|
function renderAttestationSummary(
|
|
943
944
|
config: ChainForkConfig,
|
|
945
|
+
fork: ForkName,
|
|
944
946
|
rootCache: RootHexCache,
|
|
945
947
|
summary: AttestationSummary | undefined,
|
|
946
948
|
flags: ParticipationFlags
|
|
@@ -1043,7 +1045,7 @@ function renderAttestationSummary(
|
|
|
1043
1045
|
}
|
|
1044
1046
|
|
|
1045
1047
|
const submittedLate =
|
|
1046
|
-
summary.poolSubmitDelayMinSec > config.getSlotComponentDurationMs(LATE_ATTESTATION_SUBMISSION_BPS) / 1000;
|
|
1048
|
+
summary.poolSubmitDelayMinSec > config.getSlotComponentDurationMs(fork, LATE_ATTESTATION_SUBMISSION_BPS) / 1000;
|
|
1047
1049
|
|
|
1048
1050
|
const aggregateInclusion = summary.aggregateInclusionDelaysSec.length > 0;
|
|
1049
1051
|
|
|
@@ -1178,7 +1180,8 @@ function renderBlockProposalSummary(
|
|
|
1178
1180
|
|
|
1179
1181
|
if (
|
|
1180
1182
|
proposal.poolSubmitDelaySec !== null &&
|
|
1181
|
-
proposal.poolSubmitDelaySec >
|
|
1183
|
+
proposal.poolSubmitDelaySec >
|
|
1184
|
+
config.getSlotComponentDurationMs(config.getForkName(proposalSlot), LATE_BLOCK_SUBMISSION_BPS) / 1000
|
|
1182
1185
|
) {
|
|
1183
1186
|
out += "_late";
|
|
1184
1187
|
}
|
|
@@ -184,7 +184,7 @@ export class BlockArchiveRepository extends Repository<Slot, SignedBeaconBlock>
|
|
|
184
184
|
async remove(value: SignedBeaconBlock): Promise<void> {
|
|
185
185
|
await Promise.all([
|
|
186
186
|
super.remove(value),
|
|
187
|
-
deleteRootIndex(this.db, this.config.getForkTypes(value.message.slot).
|
|
187
|
+
deleteRootIndex(this.db, this.config.getForkTypes(value.message.slot).BeaconBlock, value),
|
|
188
188
|
deleteParentRootIndex(this.db, value),
|
|
189
189
|
]);
|
|
190
190
|
}
|
|
@@ -193,7 +193,7 @@ export class BlockArchiveRepository extends Repository<Slot, SignedBeaconBlock>
|
|
|
193
193
|
await Promise.all([
|
|
194
194
|
super.batchRemove(values),
|
|
195
195
|
...values.map((value) =>
|
|
196
|
-
deleteRootIndex(this.db, this.config.getForkTypes(value.message.slot).
|
|
196
|
+
deleteRootIndex(this.db, this.config.getForkTypes(value.message.slot).BeaconBlock, value)
|
|
197
197
|
),
|
|
198
198
|
...values.map((value) => deleteParentRootIndex(this.db, value)),
|
|
199
199
|
]);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Db, encodeKey} from "@lodestar/db";
|
|
2
2
|
import {ForkAll} from "@lodestar/params";
|
|
3
|
-
import {Root, SSZTypesFor, SignedBeaconBlock, Slot
|
|
3
|
+
import {Root, SSZTypesFor, SignedBeaconBlock, Slot} from "@lodestar/types";
|
|
4
4
|
import {Bucket, getBucketNameByValue} from "../buckets.js";
|
|
5
5
|
|
|
6
6
|
export const rootIndexBucketId = getBucketNameByValue(Bucket.index_blockArchiveRootIndex);
|
|
@@ -16,10 +16,9 @@ export async function getParentRootIndex(db: Db, parentRoot: Root): Promise<Uint
|
|
|
16
16
|
|
|
17
17
|
export async function deleteRootIndex(
|
|
18
18
|
db: Db,
|
|
19
|
-
|
|
19
|
+
beaconBlockType: SSZTypesFor<ForkAll, "BeaconBlock">,
|
|
20
20
|
block: SignedBeaconBlock
|
|
21
21
|
): Promise<void> {
|
|
22
|
-
const beaconBlockType = (signedBeaconBlockType as typeof ssz.phase0.SignedBeaconBlock).fields.message;
|
|
23
22
|
return db.delete(getRootIndexKey(beaconBlockType.hashTreeRoot(block.message)), {bucketId: rootIndexBucketId});
|
|
24
23
|
}
|
|
25
24
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {byteArrayEquals} from "@lodestar/utils";
|
|
2
|
+
import {VersionedHashes} from "./interface.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Preserve Deneb's is_valid_versioned_hashes check when the REST envelope omits expected hashes.
|
|
6
|
+
* EIP-4844 encodes blob_versioned_hashes at index 10 of the signed type-3 transaction's RLP list.
|
|
7
|
+
* Skip unrelated fields without decoding or copying them, including untrusted nested access lists.
|
|
8
|
+
* The EL remains responsible for the other transaction validity checks.
|
|
9
|
+
*/
|
|
10
|
+
export function isValidBlobVersionedHashes(transactions: Uint8Array[], expected: VersionedHashes): boolean {
|
|
11
|
+
let index = 0;
|
|
12
|
+
for (const transaction of transactions) {
|
|
13
|
+
if (transaction.length === 0) return false;
|
|
14
|
+
if (transaction[0] !== 0x03) continue;
|
|
15
|
+
|
|
16
|
+
const outer = readRlpItem(transaction, 1, transaction.length);
|
|
17
|
+
if (!outer?.isList || outer.end !== transaction.length) return false;
|
|
18
|
+
|
|
19
|
+
let offset = outer.start;
|
|
20
|
+
for (let fieldIndex = 0; fieldIndex < 14; fieldIndex++) {
|
|
21
|
+
const field = readRlpItem(transaction, offset, outer.end);
|
|
22
|
+
if (field === null) return false;
|
|
23
|
+
if (fieldIndex === 10) {
|
|
24
|
+
if (!field.isList) return false;
|
|
25
|
+
// A canonical RLP-encoded Bytes32 is exactly the 0xa0 prefix followed by 32 bytes.
|
|
26
|
+
const count = (field.end - field.start) / 33;
|
|
27
|
+
if (!Number.isInteger(count) || index + count > expected.length) return false;
|
|
28
|
+
for (let hashOffset = field.start; hashOffset < field.end; hashOffset += 33) {
|
|
29
|
+
if (
|
|
30
|
+
transaction[hashOffset] !== 0xa0 ||
|
|
31
|
+
!byteArrayEquals(transaction.subarray(hashOffset + 1, hashOffset + 33), expected[index])
|
|
32
|
+
) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
index++;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
offset = field.end;
|
|
39
|
+
}
|
|
40
|
+
if (offset !== outer.end) return false;
|
|
41
|
+
}
|
|
42
|
+
return index === expected.length;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Read one RLP item's boundaries without descending into lists. */
|
|
46
|
+
function readRlpItem(
|
|
47
|
+
bytes: Uint8Array,
|
|
48
|
+
offset: number,
|
|
49
|
+
limit: number
|
|
50
|
+
): {start: number; end: number; isList: boolean} | null {
|
|
51
|
+
if (offset >= limit) return null;
|
|
52
|
+
const prefix = bytes[offset];
|
|
53
|
+
if (prefix < 0x80) return {start: offset, end: offset + 1, isList: false};
|
|
54
|
+
|
|
55
|
+
const isList = prefix >= 0xc0;
|
|
56
|
+
const lengthCode = prefix - (isList ? 0xc0 : 0x80);
|
|
57
|
+
let start = offset + 1;
|
|
58
|
+
let length = lengthCode;
|
|
59
|
+
if (lengthCode > 55) {
|
|
60
|
+
const lengthBytes = lengthCode - 55;
|
|
61
|
+
start += lengthBytes;
|
|
62
|
+
if (start > limit || bytes[offset + 1] === 0) return null;
|
|
63
|
+
length = 0;
|
|
64
|
+
for (let i = offset + 1; i < start; i++) {
|
|
65
|
+
length = length * 256 + bytes[i];
|
|
66
|
+
}
|
|
67
|
+
if (length <= 55) return null;
|
|
68
|
+
}
|
|
69
|
+
if (length > limit - start) return null;
|
|
70
|
+
if (!isList && length === 1 && bytes[start] < 0x80) return null;
|
|
71
|
+
return {start, end: start + length, isList};
|
|
72
|
+
}
|