@lodestar/beacon-node 1.45.0-dev.fadf0fbb1f → 1.46.0-dev.8fc4e297d2
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 +186 -57
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/index.d.ts +1 -1
- package/lib/api/impl/beacon/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +4 -0
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/index.d.ts +1 -1
- package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/index.js +2 -2
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +2 -1
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +9 -1
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +2 -2
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +2 -2
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/proof/index.d.ts +1 -1
- package/lib/api/impl/proof/index.d.ts.map +1 -1
- package/lib/api/impl/proof/index.js +2 -2
- package/lib/api/impl/proof/index.js.map +1 -1
- package/lib/api/impl/utils.d.ts +23 -0
- package/lib/api/impl/utils.d.ts.map +1 -1
- package/lib/api/impl/utils.js +44 -1
- package/lib/api/impl/utils.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts +0 -14
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +192 -143
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/rest/base.d.ts.map +1 -1
- package/lib/api/rest/base.js +14 -3
- package/lib/api/rest/base.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +3 -21
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +13 -5
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/builderCircuitBreaker.d.ts +31 -0
- package/lib/chain/builderCircuitBreaker.d.ts.map +1 -0
- package/lib/chain/builderCircuitBreaker.js +59 -0
- package/lib/chain/builderCircuitBreaker.js.map +1 -0
- package/lib/chain/chain.d.ts +2 -0
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +26 -2
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +48 -6
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +25 -4
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +11 -0
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +2 -0
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/errors/proposerPreferences.d.ts +14 -1
- package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/errors/proposerPreferences.js +2 -0
- package/lib/chain/errors/proposerPreferences.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -0
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +11 -6
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/lightClient/proofs.d.ts.map +1 -1
- package/lib/chain/lightClient/proofs.js +28 -2
- package/lib/chain/lightClient/proofs.js.map +1 -1
- package/lib/chain/lightClient/types.d.ts +3 -1
- package/lib/chain/lightClient/types.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.js +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
- package/lib/chain/options.d.ts +4 -0
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +12 -7
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/validation/aggregateAndProof.js +10 -6
- 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 +10 -6
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +53 -4
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +13 -12
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +29 -0
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts +9 -2
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/validation/proposerPreferences.js +64 -11
- package/lib/chain/validation/proposerPreferences.js.map +1 -1
- package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/aggregateAndProof.js +2 -3
- package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
- package/lib/db/repositories/lightclientSyncCommitteeWitness.d.ts.map +1 -1
- package/lib/db/repositories/lightclientSyncCommitteeWitness.js +42 -7
- package/lib/db/repositories/lightclientSyncCommitteeWitness.js.map +1 -1
- package/lib/execution/builder/http.d.ts +18 -0
- package/lib/execution/builder/http.d.ts.map +1 -1
- package/lib/execution/builder/http.js +20 -11
- package/lib/execution/builder/http.js.map +1 -1
- package/lib/metrics/metrics/beacon.d.ts +6 -0
- package/lib/metrics/metrics/beacon.d.ts.map +1 -1
- package/lib/metrics/metrics/beacon.js +18 -0
- package/lib/metrics/metrics/beacon.js.map +1 -1
- package/lib/network/core/metrics.d.ts +65 -0
- package/lib/network/core/metrics.d.ts.map +1 -1
- package/lib/network/core/metrics.js +94 -0
- package/lib/network/core/metrics.js.map +1 -1
- package/lib/network/discv5/utils.d.ts.map +1 -1
- package/lib/network/discv5/utils.js +12 -3
- package/lib/network/discv5/utils.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts +2 -2
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +22 -9
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +4 -3
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +80 -232
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +47 -4
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/interface.d.ts +4 -1
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +4 -1
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +19 -11
- package/lib/network/network.js.map +1 -1
- package/lib/network/peers/peerManager.d.ts.map +1 -1
- package/lib/network/peers/peerManager.js +10 -0
- package/lib/network/peers/peerManager.js.map +1 -1
- package/lib/network/peers/score/score.d.ts +3 -1
- package/lib/network/peers/score/score.d.ts.map +1 -1
- package/lib/network/peers/score/score.js +6 -1
- package/lib/network/peers/score/score.js.map +1 -1
- package/lib/network/peers/score/store.d.ts.map +1 -1
- package/lib/network/peers/score/store.js +6 -1
- package/lib/network/peers/score/store.js.map +1 -1
- package/lib/network/peers/utils/prioritizePeers.d.ts.map +1 -1
- package/lib/network/peers/utils/prioritizePeers.js +14 -0
- package/lib/network/peers/utils/prioritizePeers.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +16 -6
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +4 -2
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/index.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/index.js +20 -11
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/util.d.ts +1 -0
- package/lib/network/util.d.ts.map +1 -1
- package/lib/network/util.js +4 -0
- package/lib/network/util.js.map +1 -1
- package/lib/sync/sync.d.ts.map +1 -1
- package/lib/sync/sync.js +7 -0
- package/lib/sync/sync.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +7 -2
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/execution.js +1 -1
- package/lib/util/execution.js.map +1 -1
- package/package.json +23 -21
- package/src/api/impl/beacon/blocks/index.ts +221 -63
- package/src/api/impl/beacon/index.ts +1 -1
- package/src/api/impl/beacon/pool/index.ts +5 -0
- package/src/api/impl/beacon/state/index.ts +3 -2
- package/src/api/impl/beacon/state/utils.ts +11 -0
- package/src/api/impl/debug/index.ts +3 -2
- package/src/api/impl/lodestar/index.ts +2 -2
- package/src/api/impl/proof/index.ts +2 -2
- package/src/api/impl/utils.ts +51 -1
- package/src/api/impl/validator/index.ts +224 -157
- package/src/api/rest/base.ts +17 -3
- package/src/chain/blocks/importBlock.ts +1 -23
- package/src/chain/blocks/utils/chainSegment.ts +16 -5
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +1 -1
- package/src/chain/blocks/verifyBlocksSanityChecks.ts +1 -1
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +2 -2
- package/src/chain/builderCircuitBreaker.ts +84 -0
- package/src/chain/chain.ts +38 -2
- package/src/chain/errors/blockError.ts +44 -7
- package/src/chain/errors/executionPayloadEnvelope.ts +9 -0
- package/src/chain/errors/proposerPreferences.ts +16 -1
- package/src/chain/interface.ts +2 -0
- package/src/chain/lightClient/index.ts +12 -7
- package/src/chain/lightClient/proofs.ts +36 -1
- package/src/chain/lightClient/types.ts +3 -1
- package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
- package/src/chain/opPools/proposerPreferencesPool.ts +1 -1
- package/src/chain/options.ts +4 -0
- package/src/chain/prepareNextSlot.ts +11 -7
- package/src/chain/validation/aggregateAndProof.ts +12 -6
- package/src/chain/validation/attestation.ts +12 -6
- package/src/chain/validation/block.ts +69 -4
- package/src/chain/validation/executionPayloadBid.ts +16 -11
- package/src/chain/validation/executionPayloadEnvelope.ts +37 -0
- package/src/chain/validation/proposerPreferences.ts +74 -11
- package/src/chain/validation/signatureSets/aggregateAndProof.ts +3 -3
- package/src/db/repositories/lightclientSyncCommitteeWitness.ts +57 -9
- package/src/execution/builder/http.ts +30 -17
- package/src/metrics/metrics/beacon.ts +19 -0
- package/src/network/core/metrics.ts +94 -0
- package/src/network/discv5/utils.ts +11 -3
- package/src/network/gossip/encoding.ts +20 -7
- package/src/network/gossip/gossipsub.ts +9 -3
- package/src/network/gossip/topic.ts +58 -4
- package/src/network/interface.ts +3 -1
- package/src/network/network.ts +24 -15
- package/src/network/peers/peerManager.ts +11 -0
- package/src/network/peers/score/score.ts +8 -1
- package/src/network/peers/score/store.ts +8 -1
- package/src/network/peers/utils/prioritizePeers.ts +15 -0
- package/src/network/processor/gossipHandlers.ts +17 -6
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +4 -2
- package/src/network/reqresp/handlers/index.ts +21 -12
- package/src/network/util.ts +5 -0
- package/src/sync/sync.ts +10 -0
- package/src/sync/unknownBlock.ts +8 -2
- package/src/util/execution.ts +1 -1
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
ssz,
|
|
51
51
|
} from "@lodestar/types";
|
|
52
52
|
import {
|
|
53
|
+
GWEI_TO_WEI,
|
|
53
54
|
TimeoutError,
|
|
54
55
|
defer,
|
|
55
56
|
formatWeiToEth,
|
|
@@ -82,7 +83,6 @@ import {ZERO_HASH} from "../../../constants/index.js";
|
|
|
82
83
|
import {BuilderStatus, NoBidReceived} from "../../../execution/builder/http.js";
|
|
83
84
|
import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossipHandlers.js";
|
|
84
85
|
import {CommitteeSubscription} from "../../../network/subnets/index.js";
|
|
85
|
-
import {SyncState} from "../../../sync/index.js";
|
|
86
86
|
import {callInNextEventLoop} from "../../../util/eventLoop.js";
|
|
87
87
|
import {isOptimisticBlock} from "../../../util/forkChoice.js";
|
|
88
88
|
import {getBlockGraffiti, toGraffitiBytes} from "../../../util/graffiti.js";
|
|
@@ -91,23 +91,9 @@ import {ApiOptions} from "../../options.js";
|
|
|
91
91
|
import {getStateResponseWithRegen} from "../beacon/state/utils.js";
|
|
92
92
|
import {ApiError, FailureList, IndexedError, NodeIsSyncing, OnlySupportedByDVT} from "../errors.js";
|
|
93
93
|
import {ApiModules} from "../types.js";
|
|
94
|
+
import {notWhileSyncing} from "../utils.js";
|
|
94
95
|
import {computeSubnetForCommitteesAtSlot, getPubkeysForIndices, selectBlockProductionSource} from "./utils.js";
|
|
95
96
|
|
|
96
|
-
/**
|
|
97
|
-
* If the node is within this many epochs from the head, we declare it to be synced regardless of
|
|
98
|
-
* the network sync state.
|
|
99
|
-
*
|
|
100
|
-
* This helps prevent attacks where nodes can convince us that we're syncing some non-existent
|
|
101
|
-
* finalized head.
|
|
102
|
-
*
|
|
103
|
-
* TODO: Lighthouse uses 8 for the attack described above. However, 8 kills Lodestar since validators
|
|
104
|
-
* can trigger regen to fast-forward head state 8 epochs to be immediately invalidated as sync sets
|
|
105
|
-
* a new head. Then the checkpoint state cache grows unbounded with very different states (because
|
|
106
|
-
* they are 8 epochs apart) and causes an OOM. Research a proper solution once regen and the state
|
|
107
|
-
* caches are better.
|
|
108
|
-
*/
|
|
109
|
-
export const SYNC_TOLERANCE_EPOCHS = 1;
|
|
110
|
-
|
|
111
97
|
/**
|
|
112
98
|
* Cutoff time to wait from start of the slot for execution and builder block production apis to resolve.
|
|
113
99
|
* Post this time, race execution and builder to pick whatever resolves first.
|
|
@@ -116,7 +102,7 @@ export const SYNC_TOLERANCE_EPOCHS = 1;
|
|
|
116
102
|
* A cutoff of 2 seconds gives enough time and if there are unexpected delays it ensures we publish
|
|
117
103
|
* in time as proposals post 4 seconds into the slot will likely be orphaned due to proposer boost reorg.
|
|
118
104
|
*
|
|
119
|
-
* TODO GLOAS: re-evaluate cutoff timing
|
|
105
|
+
* TODO GLOAS: re-evaluate cutoff timing due to attestation deadline changes in gloas
|
|
120
106
|
*/
|
|
121
107
|
const BLOCK_PRODUCTION_RACE_CUTOFF_MS = 2_000;
|
|
122
108
|
/** Overall timeout for execution and block production apis */
|
|
@@ -341,36 +327,6 @@ export function getValidatorApi(
|
|
|
341
327
|
return null;
|
|
342
328
|
}
|
|
343
329
|
|
|
344
|
-
/**
|
|
345
|
-
* Reject any request while the node is syncing
|
|
346
|
-
*/
|
|
347
|
-
function notWhileSyncing(): void {
|
|
348
|
-
// Consider node synced before or close to genesis
|
|
349
|
-
if (chain.clock.currentSlot < SLOTS_PER_EPOCH) {
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const syncState = sync.state;
|
|
354
|
-
switch (syncState) {
|
|
355
|
-
case SyncState.SyncingFinalized:
|
|
356
|
-
case SyncState.SyncingHead: {
|
|
357
|
-
const currentSlot = chain.clock.currentSlot;
|
|
358
|
-
const headSlot = chain.forkChoice.getHead().slot;
|
|
359
|
-
if (currentSlot - headSlot > SYNC_TOLERANCE_EPOCHS * SLOTS_PER_EPOCH) {
|
|
360
|
-
throw new NodeIsSyncing(`headSlot ${headSlot} currentSlot ${currentSlot}`);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
case SyncState.Synced:
|
|
367
|
-
return;
|
|
368
|
-
|
|
369
|
-
case SyncState.Stalled:
|
|
370
|
-
throw new NodeIsSyncing("waiting for peers");
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
330
|
/**
|
|
375
331
|
* Post merge, the CL and EL could be out of step in the sync, and could result in
|
|
376
332
|
* Syncing status of the chain head. To be precise:
|
|
@@ -573,7 +529,17 @@ export function getValidatorApi(
|
|
|
573
529
|
builderBoostFactor?: bigint,
|
|
574
530
|
{feeRecipient, builderSelection, strictFeeRecipientCheck}: routes.validator.ExtraProduceBlockOpts = {}
|
|
575
531
|
): Promise<ProduceBlindedBlockOrBlockContentsRes> {
|
|
576
|
-
|
|
532
|
+
builderSelection = builderSelection ?? routes.validator.BuilderSelection.MaxProfit;
|
|
533
|
+
if (builderSelection === routes.validator.BuilderSelection.BuilderOnly) {
|
|
534
|
+
logger.warn("Builder selection builderonly is no longer supported, treating as builderalways");
|
|
535
|
+
builderSelection = routes.validator.BuilderSelection.BuilderAlways;
|
|
536
|
+
}
|
|
537
|
+
builderBoostFactor = builderBoostFactor ?? BigInt(100);
|
|
538
|
+
if (builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) {
|
|
539
|
+
throw new ApiError(400, `Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR`);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
notWhileSyncing(chain, sync.state);
|
|
577
543
|
await waitForSlot(slot); // Must never request for a future slot > currentSlot
|
|
578
544
|
|
|
579
545
|
const parentBlock = chain.getProposerHead(slot);
|
|
@@ -583,36 +549,12 @@ export function getValidatorApi(
|
|
|
583
549
|
metrics?.blockProductionSlotDelta.set(slot - parentSlot);
|
|
584
550
|
|
|
585
551
|
const fork = config.getForkName(slot);
|
|
586
|
-
// set some sensible opts
|
|
587
|
-
// builderSelection will be deprecated and will run in mode MaxProfit if builder is enabled
|
|
588
|
-
// and the actual selection will be determined using builderBoostFactor passed by the validator
|
|
589
|
-
builderSelection = builderSelection ?? routes.validator.BuilderSelection.MaxProfit;
|
|
590
|
-
builderBoostFactor = builderBoostFactor ?? BigInt(100);
|
|
591
|
-
if (builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) {
|
|
592
|
-
throw new ApiError(400, `Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR`);
|
|
593
|
-
}
|
|
594
552
|
|
|
595
553
|
const isBuilderEnabled =
|
|
596
554
|
ForkSeq[fork] >= ForkSeq.bellatrix &&
|
|
597
555
|
chain.executionBuilder !== undefined &&
|
|
598
556
|
builderSelection !== routes.validator.BuilderSelection.ExecutionOnly;
|
|
599
557
|
|
|
600
|
-
// At any point either the builder or execution or both flows should be active.
|
|
601
|
-
//
|
|
602
|
-
// Ideally such a scenario should be prevented on startup, but proposerSettingsFile or keymanager
|
|
603
|
-
// configurations could cause a validator pubkey to have builder disabled with builder selection builder only
|
|
604
|
-
// (TODO: independently make sure such an options update is not successful for a validator pubkey)
|
|
605
|
-
//
|
|
606
|
-
// So if builder is disabled ignore builder selection of builder only if caused by user mistake
|
|
607
|
-
// https://github.com/ChainSafe/lodestar/issues/6338
|
|
608
|
-
const isEngineEnabled = !isBuilderEnabled || builderSelection !== routes.validator.BuilderSelection.BuilderOnly;
|
|
609
|
-
|
|
610
|
-
if (!isEngineEnabled && !isBuilderEnabled) {
|
|
611
|
-
throw Error(
|
|
612
|
-
`Internal Error: Neither builder nor execution proposal flow activated isBuilderEnabled=${isBuilderEnabled} builderSelection=${builderSelection}`
|
|
613
|
-
);
|
|
614
|
-
}
|
|
615
|
-
|
|
616
558
|
const graffitiBytes = toGraffitiBytes(
|
|
617
559
|
getBlockGraffiti(graffiti, getLodestarClientVersion(opts), chain.executionEngine.clientVersion, {
|
|
618
560
|
private: opts.private,
|
|
@@ -627,7 +569,6 @@ export function getValidatorApi(
|
|
|
627
569
|
fork,
|
|
628
570
|
builderSelection,
|
|
629
571
|
isBuilderEnabled,
|
|
630
|
-
isEngineEnabled,
|
|
631
572
|
strictFeeRecipientCheck,
|
|
632
573
|
// winston logger doesn't like bigint
|
|
633
574
|
builderBoostFactor: `${builderBoostFactor}`,
|
|
@@ -653,27 +594,25 @@ export function getValidatorApi(
|
|
|
653
594
|
})
|
|
654
595
|
: Promise.reject(new Error("Builder disabled"));
|
|
655
596
|
|
|
656
|
-
const enginePromise =
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
})
|
|
676
|
-
: Promise.reject(new Error("Engine disabled"));
|
|
597
|
+
const enginePromise = produceEngineBlockContents(slot, randaoReveal, graffitiBytes, {
|
|
598
|
+
feeRecipient,
|
|
599
|
+
strictFeeRecipientCheck,
|
|
600
|
+
commonBlockBodyPromise,
|
|
601
|
+
parentBlock,
|
|
602
|
+
}).then((engineBlock) => {
|
|
603
|
+
// Once the engine returns a block, in the event of either:
|
|
604
|
+
// - suspected builder censorship
|
|
605
|
+
// - builder boost factor set to 0 or builder selection `executionalways`
|
|
606
|
+
// we don't need to wait for builder block as engine block will always be selected
|
|
607
|
+
if (
|
|
608
|
+
engineBlock.shouldOverrideBuilder ||
|
|
609
|
+
builderBoostFactor === BigInt(0) ||
|
|
610
|
+
builderSelection === routes.validator.BuilderSelection.ExecutionAlways
|
|
611
|
+
) {
|
|
612
|
+
controller.abort();
|
|
613
|
+
}
|
|
614
|
+
return engineBlock;
|
|
615
|
+
});
|
|
677
616
|
|
|
678
617
|
// Calculate cutoff time based on start of the slot
|
|
679
618
|
const cutoffMs = Math.max(0, BLOCK_PRODUCTION_RACE_CUTOFF_MS - chain.clock.msFromSlot(slot));
|
|
@@ -720,30 +659,24 @@ export function getValidatorApi(
|
|
|
720
659
|
throw Error("Builder and engine both failed to produce the block within timeout");
|
|
721
660
|
}
|
|
722
661
|
|
|
723
|
-
if (builder.status === "pending" && !isEngineEnabled) {
|
|
724
|
-
throw Error("Builder failed to produce the block within timeout");
|
|
725
|
-
}
|
|
726
|
-
|
|
727
662
|
if (engine.status === "pending" && !isBuilderEnabled) {
|
|
728
663
|
throw Error("Engine failed to produce the block within timeout");
|
|
729
664
|
}
|
|
730
665
|
|
|
731
|
-
if (
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
{
|
|
736
|
-
...loggerContext,
|
|
737
|
-
durationMs: engine.durationMs,
|
|
738
|
-
},
|
|
739
|
-
engine.reason
|
|
740
|
-
);
|
|
741
|
-
} else if (engine.status === "pending") {
|
|
742
|
-
logger.warn("Engine failed to produce the block within cutoff time", {
|
|
666
|
+
if (engine.status === "rejected") {
|
|
667
|
+
logger.warn(
|
|
668
|
+
"Engine failed to produce the block",
|
|
669
|
+
{
|
|
743
670
|
...loggerContext,
|
|
744
|
-
|
|
745
|
-
}
|
|
746
|
-
|
|
671
|
+
durationMs: engine.durationMs,
|
|
672
|
+
},
|
|
673
|
+
engine.reason
|
|
674
|
+
);
|
|
675
|
+
} else if (engine.status === "pending") {
|
|
676
|
+
logger.warn("Engine failed to produce the block within cutoff time", {
|
|
677
|
+
...loggerContext,
|
|
678
|
+
cutoffMs,
|
|
679
|
+
});
|
|
747
680
|
}
|
|
748
681
|
|
|
749
682
|
if (isBuilderEnabled) {
|
|
@@ -772,14 +705,12 @@ export function getValidatorApi(
|
|
|
772
705
|
}
|
|
773
706
|
|
|
774
707
|
if (builder.status === "rejected" && engine.status === "rejected") {
|
|
775
|
-
throw Error(
|
|
776
|
-
`${isBuilderEnabled && isEngineEnabled ? "Builder and engine both" : isBuilderEnabled ? "Builder" : "Engine"} failed to produce the block`
|
|
777
|
-
);
|
|
708
|
+
throw Error(`${isBuilderEnabled ? "Builder and engine both" : "Engine"} failed to produce the block`);
|
|
778
709
|
}
|
|
779
710
|
|
|
780
711
|
// handle shouldOverrideBuilder separately
|
|
781
|
-
if (engine.status === "fulfilled" && engine.value.shouldOverrideBuilder) {
|
|
782
|
-
logger.
|
|
712
|
+
if (engine.status === "fulfilled" && engine.value.shouldOverrideBuilder && isBuilderEnabled) {
|
|
713
|
+
logger.warn("Selected engine block: censorship suspected in builder blocks", {
|
|
783
714
|
...loggerContext,
|
|
784
715
|
durationMs: engine.durationMs,
|
|
785
716
|
shouldOverrideBuilder: engine.value.shouldOverrideBuilder,
|
|
@@ -796,11 +727,9 @@ export function getValidatorApi(
|
|
|
796
727
|
|
|
797
728
|
if (builder.status === "fulfilled" && engine.status !== "fulfilled") {
|
|
798
729
|
const reason =
|
|
799
|
-
|
|
800
|
-
? BuilderBlockSelectionReason.
|
|
801
|
-
:
|
|
802
|
-
? BuilderBlockSelectionReason.EnginePending
|
|
803
|
-
: BuilderBlockSelectionReason.EngineError;
|
|
730
|
+
engine.status === "pending"
|
|
731
|
+
? BuilderBlockSelectionReason.EnginePending
|
|
732
|
+
: BuilderBlockSelectionReason.EngineError;
|
|
804
733
|
|
|
805
734
|
logger.info("Selected builder block: no engine block produced", {
|
|
806
735
|
reason,
|
|
@@ -910,14 +839,32 @@ export function getValidatorApi(
|
|
|
910
839
|
return {data, meta};
|
|
911
840
|
},
|
|
912
841
|
|
|
913
|
-
async produceBlockV4({
|
|
842
|
+
async produceBlockV4({
|
|
843
|
+
slot,
|
|
844
|
+
randaoReveal,
|
|
845
|
+
graffiti,
|
|
846
|
+
feeRecipient,
|
|
847
|
+
includePayload,
|
|
848
|
+
builderSelection,
|
|
849
|
+
builderBoostFactor,
|
|
850
|
+
}) {
|
|
914
851
|
const fork = config.getForkName(slot);
|
|
915
852
|
|
|
916
853
|
if (!isForkPostGloas(fork)) {
|
|
917
854
|
throw new ApiError(400, `produceBlockV4 not supported for pre-gloas fork=${fork}`);
|
|
918
855
|
}
|
|
919
856
|
|
|
920
|
-
|
|
857
|
+
builderSelection = builderSelection ?? routes.validator.BuilderSelection.MaxProfit;
|
|
858
|
+
if (builderSelection === routes.validator.BuilderSelection.BuilderOnly) {
|
|
859
|
+
logger.warn("Builder selection builderonly is no longer supported, treating as builderalways");
|
|
860
|
+
builderSelection = routes.validator.BuilderSelection.BuilderAlways;
|
|
861
|
+
}
|
|
862
|
+
builderBoostFactor = builderBoostFactor ?? BigInt(100);
|
|
863
|
+
if (builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) {
|
|
864
|
+
throw new ApiError(400, `Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR`);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
notWhileSyncing(chain, sync.state);
|
|
921
868
|
await waitForSlot(slot);
|
|
922
869
|
|
|
923
870
|
const parentBlock = chain.getProposerHead(slot);
|
|
@@ -933,12 +880,17 @@ export function getValidatorApi(
|
|
|
933
880
|
})
|
|
934
881
|
);
|
|
935
882
|
|
|
936
|
-
// TODO GLOAS:
|
|
937
|
-
// the user control bid source preferences and value comparison. Also add external builder api
|
|
938
|
-
// support when it is implemented.
|
|
883
|
+
// TODO GLOAS: add external builder api support when it is implemented
|
|
939
884
|
const isBuildingOnFull = chain.forkChoice.shouldBuildOnFull(parentBlock, slot);
|
|
940
885
|
const bidParentBlockHash = isBuildingOnFull ? parentBlock.executionPayloadBlockHash : parentBlock.parentBlockHash;
|
|
941
|
-
|
|
886
|
+
// Bids are only skipped entirely with executiononly or while the circuit breaker is active,
|
|
887
|
+
// other engine-preferring selections still build a block with the best bid as fallback in
|
|
888
|
+
// case local production fails
|
|
889
|
+
const circuitBreakerActive = chain.builderCircuitBreaker.isActive(slot);
|
|
890
|
+
const builderBid =
|
|
891
|
+
builderSelection === routes.validator.BuilderSelection.ExecutionOnly || circuitBreakerActive
|
|
892
|
+
? null
|
|
893
|
+
: chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
|
|
942
894
|
|
|
943
895
|
const logCtx = {
|
|
944
896
|
slot,
|
|
@@ -946,6 +898,9 @@ export function getValidatorApi(
|
|
|
946
898
|
parentBlockRoot: parentBlockRootHex,
|
|
947
899
|
parentBlockHash: parentBlock.executionPayloadBlockHash,
|
|
948
900
|
fork,
|
|
901
|
+
builderSelection,
|
|
902
|
+
builderBoostFactor,
|
|
903
|
+
circuitBreakerActive,
|
|
949
904
|
...(builderBid !== null
|
|
950
905
|
? {
|
|
951
906
|
bidValue: builderBid.message.value,
|
|
@@ -981,33 +936,101 @@ export function getValidatorApi(
|
|
|
981
936
|
return fn().finally(() => t?.({source}));
|
|
982
937
|
};
|
|
983
938
|
|
|
984
|
-
//
|
|
985
|
-
|
|
986
|
-
|
|
939
|
+
// Calculate cutoff time based on start of the slot, ensures a slow local payload build does
|
|
940
|
+
// not delay the proposal when a builder bid block is available (and vice versa)
|
|
941
|
+
const cutoffMs = Math.max(0, BLOCK_PRODUCTION_RACE_CUTOFF_MS - chain.clock.msFromSlot(slot));
|
|
942
|
+
|
|
943
|
+
// use abort controller to stop waiting for the bid block if the engine block will be selected
|
|
944
|
+
const controller = new AbortController();
|
|
945
|
+
|
|
946
|
+
const enginePromise: ReturnType<typeof chain.produceBlock> = timed(ProducedBlockSource.engine, () =>
|
|
947
|
+
chain.produceBlock(baseAttrs)
|
|
948
|
+
).then((engineBlock) => {
|
|
949
|
+
// No need to wait for the bid block if the engine block will always be selected due to
|
|
950
|
+
// suspected builder censorship, a builder boost factor of 0 or executionalways selection
|
|
951
|
+
if (
|
|
952
|
+
engineBlock.shouldOverrideBuilder ||
|
|
953
|
+
builderBoostFactor === BigInt(0) ||
|
|
954
|
+
builderSelection === routes.validator.BuilderSelection.ExecutionAlways
|
|
955
|
+
) {
|
|
956
|
+
controller.abort();
|
|
957
|
+
}
|
|
958
|
+
return engineBlock;
|
|
959
|
+
});
|
|
960
|
+
const bidPromise: ReturnType<typeof chain.produceBlock> =
|
|
987
961
|
builderBid !== null
|
|
988
962
|
? timed(ProducedBlockSource.builder, () => chain.produceBlock({...baseAttrs, builderBid}))
|
|
989
|
-
: Promise.reject()
|
|
990
|
-
|
|
963
|
+
: Promise.reject(new Error("No builder bid available"));
|
|
964
|
+
|
|
965
|
+
const [engineResult, bidResult] = await resolveOrRacePromises([enginePromise, bidPromise], {
|
|
966
|
+
resolveTimeoutMs: cutoffMs,
|
|
967
|
+
raceTimeoutMs: BLOCK_PRODUCTION_RACE_TIMEOUT_MS,
|
|
968
|
+
signal: controller.signal,
|
|
969
|
+
});
|
|
991
970
|
|
|
992
971
|
let bestResult: typeof engineResult | null = null;
|
|
993
972
|
let source: ProducedBlockSource = ProducedBlockSource.engine;
|
|
994
|
-
|
|
973
|
+
|
|
974
|
+
// handle shouldOverrideBuilder separately
|
|
975
|
+
if (engineResult.status === "fulfilled" && engineResult.value.shouldOverrideBuilder && builderBid !== null) {
|
|
976
|
+
source = ProducedBlockSource.engine;
|
|
977
|
+
bestResult = engineResult;
|
|
978
|
+
metrics?.blockProductionSelectionResults.inc({
|
|
979
|
+
source: ProducedBlockSource.engine,
|
|
980
|
+
reason: EngineBlockSelectionReason.BuilderCensorship,
|
|
981
|
+
});
|
|
982
|
+
logger.warn("Selected local block: censorship suspected in builder bid", logCtx);
|
|
983
|
+
} else if (engineResult.status === "fulfilled" && bidResult.status === "fulfilled") {
|
|
984
|
+
const result = selectBlockProductionSource({
|
|
985
|
+
builderSelection,
|
|
986
|
+
builderBoostFactor,
|
|
987
|
+
engineExecutionPayloadValue: engineResult.value.executionPayloadValue,
|
|
988
|
+
// The bid value is the payment to the proposer, in Gwei
|
|
989
|
+
builderExecutionPayloadValue: BigInt(builderBid?.message.value ?? 0) * GWEI_TO_WEI,
|
|
990
|
+
});
|
|
991
|
+
source = result.source;
|
|
992
|
+
metrics?.blockProductionSelectionResults.inc(result);
|
|
993
|
+
logger.info(`Selected ${source} block`, {reason: result.reason, ...logCtx});
|
|
994
|
+
bestResult = source === ProducedBlockSource.builder ? bidResult : engineResult;
|
|
995
|
+
} else if (bidResult.status === "fulfilled") {
|
|
995
996
|
source = ProducedBlockSource.builder;
|
|
996
997
|
bestResult = bidResult;
|
|
997
|
-
|
|
998
|
+
const reason =
|
|
999
|
+
engineResult.status === "pending"
|
|
1000
|
+
? BuilderBlockSelectionReason.EnginePending
|
|
1001
|
+
: BuilderBlockSelectionReason.EngineError;
|
|
1002
|
+
metrics?.blockProductionSelectionResults.inc({source: ProducedBlockSource.builder, reason});
|
|
1003
|
+
logger.info("Selected builder bid block: no local block produced", {
|
|
1004
|
+
reason,
|
|
1005
|
+
...logCtx,
|
|
1006
|
+
error: engineResult.status === "rejected" ? (engineResult.reason as Error).message : undefined,
|
|
1007
|
+
});
|
|
998
1008
|
} else if (engineResult.status === "fulfilled") {
|
|
999
1009
|
source = ProducedBlockSource.engine;
|
|
1000
1010
|
bestResult = engineResult;
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1011
|
+
const reason =
|
|
1012
|
+
builderBid === null
|
|
1013
|
+
? EngineBlockSelectionReason.BuilderNoBid
|
|
1014
|
+
: bidResult.status === "pending"
|
|
1015
|
+
? EngineBlockSelectionReason.BuilderPending
|
|
1016
|
+
: EngineBlockSelectionReason.BuilderError;
|
|
1017
|
+
metrics?.blockProductionSelectionResults.inc({source: ProducedBlockSource.engine, reason});
|
|
1018
|
+
logger.info("Selected local block: no builder bid block produced", {
|
|
1019
|
+
reason,
|
|
1020
|
+
...logCtx,
|
|
1021
|
+
error: bidResult.status === "rejected" ? (bidResult.reason as Error).message : undefined,
|
|
1022
|
+
});
|
|
1004
1023
|
}
|
|
1005
1024
|
|
|
1006
1025
|
if (bestResult === null || bestResult.status !== "fulfilled") {
|
|
1007
|
-
const engineReason = engineResult.status === "rejected" ? engineResult.reason :
|
|
1008
|
-
const bidReason =
|
|
1009
|
-
logger.error("Block production failed", {
|
|
1010
|
-
|
|
1026
|
+
const engineReason = engineResult.status === "rejected" ? engineResult.reason : engineResult.status;
|
|
1027
|
+
const bidReason = bidResult.status === "rejected" ? bidResult.reason : bidResult.status;
|
|
1028
|
+
logger.error("Block production failed", {
|
|
1029
|
+
...logCtx,
|
|
1030
|
+
engineReason: String(engineReason),
|
|
1031
|
+
bidReason: String(bidReason),
|
|
1032
|
+
});
|
|
1033
|
+
throw Error(`Block production failed: engine=${String(engineReason)} builder=${String(bidReason)}`);
|
|
1011
1034
|
}
|
|
1012
1035
|
|
|
1013
1036
|
const {block, executionPayloadValue, consensusBlockValue} = bestResult.value;
|
|
@@ -1028,14 +1051,46 @@ export function getValidatorApi(
|
|
|
1028
1051
|
void chain.persistBlock(block, "produced_engine_block");
|
|
1029
1052
|
}
|
|
1030
1053
|
|
|
1054
|
+
// Include the payload for self-builds unless disabled (stateless flow)
|
|
1055
|
+
const isSelfBuild = source === ProducedBlockSource.engine;
|
|
1056
|
+
if (isSelfBuild && includePayload) {
|
|
1057
|
+
const produceResult = chain.blockProductionCache.get(blockRoot);
|
|
1058
|
+
if (
|
|
1059
|
+
produceResult === undefined ||
|
|
1060
|
+
!isForkPostGloas(produceResult.fork) ||
|
|
1061
|
+
produceResult.type !== BlockType.Full
|
|
1062
|
+
) {
|
|
1063
|
+
throw Error(`Missing cached block production result for produced block slot=${slot} blockRoot=${blockRoot}`);
|
|
1064
|
+
}
|
|
1065
|
+
const {executionPayload, executionRequests, blobsBundle, parentBlockRoot} = produceResult as ProduceFullGloas;
|
|
1066
|
+
|
|
1067
|
+
const blockContents: gloas.BlockContents = {
|
|
1068
|
+
block: block as gloas.BeaconBlock,
|
|
1069
|
+
executionPayloadEnvelope: {
|
|
1070
|
+
payload: executionPayload,
|
|
1071
|
+
executionRequests,
|
|
1072
|
+
builderIndex: BUILDER_INDEX_SELF_BUILD,
|
|
1073
|
+
beaconBlockRoot: fromHex(blockRoot),
|
|
1074
|
+
parentBeaconBlockRoot: parentBlockRoot,
|
|
1075
|
+
},
|
|
1076
|
+
kzgProofs: blobsBundle.proofs,
|
|
1077
|
+
blobs: blobsBundle.blobs,
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
return {
|
|
1081
|
+
data: blockContents,
|
|
1082
|
+
meta: {version: fork, consensusBlockValue, executionPayloadValue, executionPayloadIncluded: true},
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1031
1086
|
return {
|
|
1032
1087
|
data: block as gloas.BeaconBlock,
|
|
1033
|
-
meta: {version: fork, consensusBlockValue},
|
|
1088
|
+
meta: {version: fork, consensusBlockValue, executionPayloadValue, executionPayloadIncluded: false},
|
|
1034
1089
|
};
|
|
1035
1090
|
},
|
|
1036
1091
|
|
|
1037
1092
|
async produceAttestationData({committeeIndex, slot}) {
|
|
1038
|
-
notWhileSyncing();
|
|
1093
|
+
notWhileSyncing(chain, sync.state);
|
|
1039
1094
|
|
|
1040
1095
|
await waitForSlot(slot); // Must never request for a future slot > currentSlot
|
|
1041
1096
|
|
|
@@ -1116,7 +1171,7 @@ export function getValidatorApi(
|
|
|
1116
1171
|
throw new ApiError(400, `producePayloadAttestationData is not supported before Gloas fork=${fork}`);
|
|
1117
1172
|
}
|
|
1118
1173
|
|
|
1119
|
-
notWhileSyncing();
|
|
1174
|
+
notWhileSyncing(chain, sync.state);
|
|
1120
1175
|
await waitForSlot(slot);
|
|
1121
1176
|
|
|
1122
1177
|
const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
|
|
@@ -1201,7 +1256,7 @@ export function getValidatorApi(
|
|
|
1201
1256
|
},
|
|
1202
1257
|
|
|
1203
1258
|
async getProposerDuties({epoch}, _context, opts?: {v2?: boolean}) {
|
|
1204
|
-
notWhileSyncing();
|
|
1259
|
+
notWhileSyncing(chain, sync.state);
|
|
1205
1260
|
|
|
1206
1261
|
const currentEpoch = currentEpochWithDisparity();
|
|
1207
1262
|
const nextEpoch = currentEpoch + 1;
|
|
@@ -1248,7 +1303,7 @@ export function getValidatorApi(
|
|
|
1248
1303
|
// requested epoch is within that range, we can use the head state at current epoch
|
|
1249
1304
|
state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.getDuties);
|
|
1250
1305
|
} else {
|
|
1251
|
-
const res = await getStateResponseWithRegen(chain, startSlot);
|
|
1306
|
+
const res = await getStateResponseWithRegen(chain, sync, startSlot);
|
|
1252
1307
|
|
|
1253
1308
|
state = res.state instanceof Uint8Array ? chain.getHeadState().loadOtherState(res.state) : res.state;
|
|
1254
1309
|
|
|
@@ -1342,7 +1397,7 @@ export function getValidatorApi(
|
|
|
1342
1397
|
},
|
|
1343
1398
|
|
|
1344
1399
|
async getAttesterDuties({epoch, indices}) {
|
|
1345
|
-
notWhileSyncing();
|
|
1400
|
+
notWhileSyncing(chain, sync.state);
|
|
1346
1401
|
|
|
1347
1402
|
if (indices.length === 0) {
|
|
1348
1403
|
throw new ApiError(400, "No validator to get attester duties");
|
|
@@ -1402,7 +1457,7 @@ export function getValidatorApi(
|
|
|
1402
1457
|
},
|
|
1403
1458
|
|
|
1404
1459
|
async getPtcDuties({epoch, indices}) {
|
|
1405
|
-
notWhileSyncing();
|
|
1460
|
+
notWhileSyncing(chain, sync.state);
|
|
1406
1461
|
|
|
1407
1462
|
if (indices.length === 0) {
|
|
1408
1463
|
throw new ApiError(400, "No validator to get PTC duties");
|
|
@@ -1464,7 +1519,7 @@ export function getValidatorApi(
|
|
|
1464
1519
|
* @param validatorIndices an array of the validator indices for which to obtain the duties.
|
|
1465
1520
|
*/
|
|
1466
1521
|
async getSyncCommitteeDuties({epoch, indices}) {
|
|
1467
|
-
notWhileSyncing();
|
|
1522
|
+
notWhileSyncing(chain, sync.state);
|
|
1468
1523
|
|
|
1469
1524
|
if (indices.length === 0) {
|
|
1470
1525
|
throw new ApiError(400, "No validator to get attester duties");
|
|
@@ -1511,7 +1566,7 @@ export function getValidatorApi(
|
|
|
1511
1566
|
},
|
|
1512
1567
|
|
|
1513
1568
|
async getAggregatedAttestationV2({attestationDataRoot, slot, committeeIndex}) {
|
|
1514
|
-
notWhileSyncing();
|
|
1569
|
+
notWhileSyncing(chain, sync.state);
|
|
1515
1570
|
|
|
1516
1571
|
await waitForSlot(slot); // Must never request for a future slot > currentSlot
|
|
1517
1572
|
|
|
@@ -1534,7 +1589,7 @@ export function getValidatorApi(
|
|
|
1534
1589
|
},
|
|
1535
1590
|
|
|
1536
1591
|
async publishAggregateAndProofsV2({signedAggregateAndProofs}) {
|
|
1537
|
-
notWhileSyncing();
|
|
1592
|
+
notWhileSyncing(chain, sync.state);
|
|
1538
1593
|
|
|
1539
1594
|
const seenTimestampSec = Date.now() / 1000;
|
|
1540
1595
|
const failures: FailureList = [];
|
|
@@ -1595,7 +1650,7 @@ export function getValidatorApi(
|
|
|
1595
1650
|
* https://github.com/ethereum/beacon-APIs/pull/137
|
|
1596
1651
|
*/
|
|
1597
1652
|
async publishContributionAndProofs({contributionAndProofs}) {
|
|
1598
|
-
notWhileSyncing();
|
|
1653
|
+
notWhileSyncing(chain, sync.state);
|
|
1599
1654
|
|
|
1600
1655
|
const failures: FailureList = [];
|
|
1601
1656
|
|
|
@@ -1644,7 +1699,7 @@ export function getValidatorApi(
|
|
|
1644
1699
|
},
|
|
1645
1700
|
|
|
1646
1701
|
async prepareBeaconCommitteeSubnet({subscriptions}) {
|
|
1647
|
-
notWhileSyncing();
|
|
1702
|
+
notWhileSyncing(chain, sync.state);
|
|
1648
1703
|
|
|
1649
1704
|
await network.prepareBeaconCommitteeSubnets(
|
|
1650
1705
|
subscriptions.map(({validatorIndex, slot, isAggregator, committeesAtSlot, committeeIndex}) => ({
|
|
@@ -1677,7 +1732,7 @@ export function getValidatorApi(
|
|
|
1677
1732
|
* https://github.com/ethereum/beacon-APIs/pull/136
|
|
1678
1733
|
*/
|
|
1679
1734
|
async prepareSyncCommitteeSubnets({subscriptions}) {
|
|
1680
|
-
notWhileSyncing();
|
|
1735
|
+
notWhileSyncing(chain, sync.state);
|
|
1681
1736
|
|
|
1682
1737
|
// A `validatorIndex` can be in multiple subnets, so compute the CommitteeSubscription with double for loop
|
|
1683
1738
|
const subs: CommitteeSubscription[] = [];
|
|
@@ -1821,7 +1876,7 @@ export function getValidatorApi(
|
|
|
1821
1876
|
throw new ApiError(400, `getExecutionPayloadEnvelope not supported for pre-gloas fork=${fork}`);
|
|
1822
1877
|
}
|
|
1823
1878
|
|
|
1824
|
-
notWhileSyncing();
|
|
1879
|
+
notWhileSyncing(chain, sync.state);
|
|
1825
1880
|
await waitForSlot(slot);
|
|
1826
1881
|
|
|
1827
1882
|
const blockRootHex = toRootHex(beaconBlockRoot);
|
|
@@ -1839,6 +1894,18 @@ export function getValidatorApi(
|
|
|
1839
1894
|
|
|
1840
1895
|
const {executionPayload, executionRequests, parentBlockRoot} = produceResult as ProduceFullGloas;
|
|
1841
1896
|
|
|
1897
|
+
if (executionPayload === undefined) {
|
|
1898
|
+
// Blocks committing to a builder bid are cached as full but without payload data
|
|
1899
|
+
throw new ApiError(404, `No local execution payload cached for block root ${blockRootHex}`);
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
if (executionPayload.slotNumber !== slot) {
|
|
1903
|
+
throw new ApiError(
|
|
1904
|
+
404,
|
|
1905
|
+
`Cached execution payload is for slot=${executionPayload.slotNumber}, requested slot=${slot}`
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1842
1909
|
const envelope: gloas.ExecutionPayloadEnvelope = {
|
|
1843
1910
|
payload: executionPayload,
|
|
1844
1911
|
executionRequests: executionRequests,
|