@lodestar/beacon-node 1.47.0-dev.f591cb177e → 1.48.0-dev.67344272c0
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 +44 -12
- package/lib/api/impl/beacon/blocks/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 +21 -2
- package/lib/api/impl/beacon/pool/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.map +1 -1
- package/lib/api/impl/events/index.d.ts.map +1 -1
- package/lib/api/impl/events/index.js +2 -0
- package/lib/api/impl/events/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +1 -1
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +237 -49
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/impl/validator/utils.js +1 -1
- package/lib/api/impl/validator/utils.js.map +1 -1
- package/lib/api/rest/base.d.ts.map +1 -1
- package/lib/api/rest/base.js +7 -0
- package/lib/api/rest/base.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +1 -1
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +11 -9
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +21 -13
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +5 -2
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/bls/index.d.ts +1 -1
- package/lib/chain/bls/index.d.ts.map +1 -1
- package/lib/chain/bls/interface.d.ts +5 -5
- package/lib/chain/bls/interface.d.ts.map +1 -1
- package/lib/chain/bls/multithread/index.d.ts +5 -11
- package/lib/chain/bls/multithread/index.d.ts.map +1 -1
- package/lib/chain/bls/multithread/index.js +116 -101
- package/lib/chain/bls/multithread/index.js.map +1 -1
- package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
- package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
- package/lib/chain/bls/multithread/jobItem.js +10 -65
- package/lib/chain/bls/multithread/jobItem.js.map +1 -1
- package/lib/chain/bls/multithread/types.d.ts +29 -8
- package/lib/chain/bls/multithread/types.d.ts.map +1 -1
- package/lib/chain/bls/multithread/types.js +12 -0
- package/lib/chain/bls/multithread/types.js.map +1 -1
- package/lib/chain/bls/multithread/utils.d.ts +4 -0
- package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
- package/lib/chain/bls/multithread/utils.js +10 -0
- package/lib/chain/bls/multithread/utils.js.map +1 -1
- package/lib/chain/bls/multithread/worker.js +49 -23
- package/lib/chain/bls/multithread/worker.js.map +1 -1
- package/lib/chain/bls/singleThread.d.ts +4 -10
- package/lib/chain/bls/singleThread.d.ts.map +1 -1
- package/lib/chain/bls/singleThread.js +8 -45
- package/lib/chain/bls/singleThread.js.map +1 -1
- package/lib/chain/bls/utils.d.ts +4 -4
- package/lib/chain/bls/utils.d.ts.map +1 -1
- package/lib/chain/bls/utils.js +18 -19
- package/lib/chain/bls/utils.js.map +1 -1
- package/lib/chain/chain.d.ts +9 -4
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +22 -8
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +1 -0
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +6 -1
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +1 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +4 -0
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +8 -4
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/attestationPool.d.ts +1 -1
- package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/attestationPool.js +1 -1
- package/lib/chain/opPools/attestationPool.js.map +1 -1
- package/lib/chain/opPools/deferredVoluntaryExitPool.d.ts +16 -0
- package/lib/chain/opPools/deferredVoluntaryExitPool.d.ts.map +1 -0
- package/lib/chain/opPools/deferredVoluntaryExitPool.js +57 -0
- package/lib/chain/opPools/deferredVoluntaryExitPool.js.map +1 -0
- package/lib/chain/opPools/executionPayloadBidPool.d.ts +7 -2
- package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.js +4 -4
- package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
- package/lib/chain/opPools/index.d.ts +2 -1
- package/lib/chain/opPools/index.d.ts.map +1 -1
- package/lib/chain/opPools/index.js +1 -0
- package/lib/chain/opPools/index.js.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.js +3 -3
- package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
- package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
- package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
- package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
- package/lib/chain/opPools/utils.d.ts +1 -1
- package/lib/chain/opPools/utils.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +1 -1
- package/lib/chain/opPools/utils.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts +5 -0
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +47 -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 +3 -25
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +5 -2
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +3 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/regen/queued.d.ts +2 -2
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +5 -5
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
- package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
- package/lib/chain/seenCache/seenAttesters.js +25 -4
- package/lib/chain/seenCache/seenAttesters.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +28 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts +5 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +6 -0
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +47 -5
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +117 -7
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +3 -3
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +1 -4
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +1 -1
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +40 -10
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts +15 -3
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +166 -12
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
- 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 +5 -14
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.js +2 -2
- package/lib/chain/validation/proposerPreferences.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +1 -1
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validation/voluntaryExit.d.ts +9 -1
- package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +46 -1
- package/lib/chain/validation/voluntaryExit.js.map +1 -1
- package/lib/execution/builder/apiClient.d.ts +70 -0
- package/lib/execution/builder/apiClient.d.ts.map +1 -0
- package/lib/execution/builder/apiClient.js +202 -0
- package/lib/execution/builder/apiClient.js.map +1 -0
- package/lib/execution/builder/validateBid.d.ts +23 -0
- package/lib/execution/builder/validateBid.d.ts.map +1 -0
- package/lib/execution/builder/validateBid.js +119 -0
- package/lib/execution/builder/validateBid.js.map +1 -0
- package/lib/metrics/metrics/lodestar.d.ts +84 -23
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +161 -55
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +13 -0
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +37 -0
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +23 -43
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/constants.d.ts +7 -0
- package/lib/network/processor/constants.d.ts.map +1 -0
- package/lib/network/processor/constants.js +7 -0
- package/lib/network/processor/constants.js.map +1 -0
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +6 -2
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipQueues/indexed.d.ts.map +1 -1
- package/lib/network/processor/gossipQueues/indexed.js +0 -1
- package/lib/network/processor/gossipQueues/indexed.js.map +1 -1
- package/lib/network/processor/index.d.ts +3 -0
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +52 -23
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/score.d.ts.map +1 -1
- package/lib/network/reqresp/score.js +5 -11
- package/lib/network/reqresp/score.js.map +1 -1
- package/lib/network/util.d.ts +0 -1
- package/lib/network/util.d.ts.map +1 -1
- package/lib/network/util.js +0 -4
- package/lib/network/util.js.map +1 -1
- package/lib/node/deferredVoluntaryExitPublisher.d.ts +15 -0
- package/lib/node/deferredVoluntaryExitPublisher.d.ts.map +1 -0
- package/lib/node/deferredVoluntaryExitPublisher.js +38 -0
- package/lib/node/deferredVoluntaryExitPublisher.js.map +1 -0
- package/lib/node/nodejs.d.ts +2 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +7 -0
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/range/batch.d.ts +23 -5
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +61 -22
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +2 -1
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +32 -12
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.js +1 -1
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/types.d.ts +32 -0
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +33 -0
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +6 -2
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +143 -68
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +16 -11
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +3 -1
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/package.json +35 -35
- package/src/api/impl/beacon/blocks/index.ts +51 -15
- package/src/api/impl/beacon/pool/index.ts +22 -2
- package/src/api/impl/beacon/state/utils.ts +2 -1
- package/src/api/impl/events/index.ts +3 -1
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +290 -49
- package/src/api/impl/validator/utils.ts +1 -1
- package/src/api/rest/base.ts +7 -0
- package/src/chain/archiveStore/archiveStore.ts +1 -1
- package/src/chain/blocks/importExecutionPayload.ts +12 -11
- package/src/chain/blocks/index.ts +25 -13
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
- package/src/chain/blocks/verifyBlock.ts +5 -2
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
- package/src/chain/bls/index.ts +1 -1
- package/src/chain/bls/interface.ts +7 -3
- package/src/chain/bls/multithread/index.ts +148 -120
- package/src/chain/bls/multithread/jobItem.ts +12 -82
- package/src/chain/bls/multithread/types.ts +33 -8
- package/src/chain/bls/multithread/utils.ts +11 -0
- package/src/chain/bls/multithread/worker.ts +85 -27
- package/src/chain/bls/singleThread.ts +11 -55
- package/src/chain/bls/utils.ts +23 -24
- package/src/chain/chain.ts +25 -7
- package/src/chain/errors/blockError.ts +8 -2
- package/src/chain/errors/executionPayloadBid.ts +6 -0
- package/src/chain/forkChoice/index.ts +4 -0
- package/src/chain/interface.ts +8 -3
- package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
- package/src/chain/opPools/attestationPool.ts +1 -1
- package/src/chain/opPools/deferredVoluntaryExitPool.ts +65 -0
- package/src/chain/opPools/executionPayloadBidPool.ts +13 -7
- package/src/chain/opPools/index.ts +2 -1
- package/src/chain/opPools/payloadAttestationPool.ts +3 -3
- package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
- package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
- package/src/chain/opPools/utils.ts +1 -1
- package/src/chain/prepareNextSlot.ts +49 -6
- package/src/chain/produceBlock/computeNewStateRoot.ts +3 -38
- package/src/chain/produceBlock/produceBlockBody.ts +1 -1
- package/src/chain/regen/interface.ts +5 -2
- package/src/chain/regen/queued.ts +5 -5
- package/src/chain/seenCache/seenAttesters.ts +31 -5
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
- package/src/chain/stateCache/fifoBlockStateCache.ts +8 -1
- package/src/chain/stateCache/persistentCheckpointsCache.ts +133 -8
- package/src/chain/stateCache/types.ts +3 -3
- package/src/chain/validation/attestation.ts +1 -7
- package/src/chain/validation/attesterSlashing.ts +1 -8
- package/src/chain/validation/block.ts +43 -10
- package/src/chain/validation/executionPayloadBid.ts +193 -14
- package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
- package/src/chain/validation/payloadAttestationMessage.ts +6 -17
- package/src/chain/validation/proposerPreferences.ts +3 -3
- package/src/chain/validation/proposerSlashing.ts +1 -1
- package/src/chain/validation/voluntaryExit.ts +59 -2
- package/src/execution/builder/apiClient.ts +264 -0
- package/src/execution/builder/validateBid.ts +181 -0
- package/src/metrics/metrics/lodestar.ts +176 -61
- package/src/network/gossip/topic.ts +38 -0
- package/src/network/network.ts +29 -54
- package/src/network/processor/constants.ts +6 -0
- package/src/network/processor/gossipHandlers.ts +6 -2
- package/src/network/processor/gossipQueues/indexed.ts +0 -1
- package/src/network/processor/index.ts +67 -30
- package/src/network/reqresp/score.ts +5 -11
- package/src/network/util.ts +0 -5
- package/src/node/deferredVoluntaryExitPublisher.ts +54 -0
- package/src/node/nodejs.ts +10 -1
- package/src/sync/range/batch.ts +83 -28
- package/src/sync/range/chain.ts +35 -13
- package/src/sync/range/range.ts +1 -1
- package/src/sync/types.ts +33 -0
- package/src/sync/unknownBlock.ts +167 -73
- package/src/sync/utils/downloadByRange.ts +21 -12
- package/src/sync/utils/downloadByRoot.ts +3 -1
- package/lib/chain/bls/maybeBatch.d.ts +0 -12
- package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
- package/lib/chain/bls/maybeBatch.js +0 -35
- package/lib/chain/bls/maybeBatch.js.map +0 -1
- package/src/chain/bls/maybeBatch.ts +0 -45
|
@@ -52,12 +52,16 @@ import {
|
|
|
52
52
|
import {
|
|
53
53
|
GWEI_TO_WEI,
|
|
54
54
|
TimeoutError,
|
|
55
|
+
byteArrayEquals,
|
|
55
56
|
defer,
|
|
56
57
|
formatWeiToEth,
|
|
57
58
|
fromHex,
|
|
59
|
+
prettyGweiToEth,
|
|
58
60
|
prettyWeiToEth,
|
|
59
61
|
resolveOrRacePromises,
|
|
62
|
+
sleep,
|
|
60
63
|
toHex,
|
|
64
|
+
toPrintableUrl,
|
|
61
65
|
toRootHex,
|
|
62
66
|
} from "@lodestar/utils";
|
|
63
67
|
import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator";
|
|
@@ -72,6 +76,7 @@ import {
|
|
|
72
76
|
SyncCommitteeErrorCode,
|
|
73
77
|
} from "../../../chain/errors/index.js";
|
|
74
78
|
import {ChainEvent, CommonBlockBody} from "../../../chain/index.js";
|
|
79
|
+
import {PooledExecutionPayloadBid} from "../../../chain/opPools/index.js";
|
|
75
80
|
import {PREPARE_NEXT_SLOT_BPS} from "../../../chain/prepareNextSlot.js";
|
|
76
81
|
import {BlockType, ProduceFullDeneb, ProduceFullGloas} from "../../../chain/produceBlock/index.js";
|
|
77
82
|
import {RegenCaller} from "../../../chain/regen/index.js";
|
|
@@ -80,7 +85,9 @@ import {validateApiAggregateAndProof} from "../../../chain/validation/index.js";
|
|
|
80
85
|
import {validateGossipProposerPreferences} from "../../../chain/validation/proposerPreferences.js";
|
|
81
86
|
import {validateSyncCommitteeGossipContributionAndProof} from "../../../chain/validation/syncCommitteeContributionAndProof.js";
|
|
82
87
|
import {ZERO_HASH} from "../../../constants/index.js";
|
|
88
|
+
import {BUILDER_BID_DEADLINE_MS, BuilderApiBid, decodeBuilderUrl} from "../../../execution/builder/apiClient.js";
|
|
83
89
|
import {BuilderStatus, NoBidReceived} from "../../../execution/builder/http.js";
|
|
90
|
+
import {getBuilderBidTotalGwei, validateBuilderApiExecutionPayloadBid} from "../../../execution/builder/validateBid.js";
|
|
84
91
|
import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossipHandlers.js";
|
|
85
92
|
import {CommitteeSubscription} from "../../../network/subnets/index.js";
|
|
86
93
|
import {callInNextEventLoop} from "../../../util/eventLoop.js";
|
|
@@ -112,6 +119,55 @@ import {
|
|
|
112
119
|
const BLOCK_PRODUCTION_RACE_CUTOFF_MS = 2_000;
|
|
113
120
|
/** Overall timeout for execution and block production apis */
|
|
114
121
|
const BLOCK_PRODUCTION_RACE_TIMEOUT_MS = 12_000;
|
|
122
|
+
/** Rejection message of the bid block branch when there is no viable bid to commit to */
|
|
123
|
+
const NO_BID_AVAILABLE = "No builder bid available";
|
|
124
|
+
|
|
125
|
+
type BidCandidate = {
|
|
126
|
+
signedBid: gloas.SignedExecutionPayloadBid;
|
|
127
|
+
/** Total payment in Gwei, counting the execution payment at most at the entry's cap */
|
|
128
|
+
totalGwei: bigint;
|
|
129
|
+
boostFactor: bigint;
|
|
130
|
+
url?: string;
|
|
131
|
+
/** Time in milliseconds from the slot start when the bid was received */
|
|
132
|
+
receivedMs: number;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Return the best bid by boosted total payment. A candidate with the max boost factor is
|
|
137
|
+
* preferred over any other regardless of value, ties prefer a builder api bid over the
|
|
138
|
+
* p2p bid, and the earlier received bid between builder api bids.
|
|
139
|
+
*/
|
|
140
|
+
function selectBestBid(candidates: BidCandidate[]): BidCandidate | null {
|
|
141
|
+
const boostedValue = ({totalGwei, boostFactor}: BidCandidate): bigint => boostFactor * totalGwei;
|
|
142
|
+
let best: BidCandidate | null = null;
|
|
143
|
+
for (const candidate of candidates) {
|
|
144
|
+
if (best === null) {
|
|
145
|
+
best = candidate;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
// Preserve max boost preference before comparing bid values
|
|
149
|
+
const candidateIsMaxBoost = candidate.boostFactor === MAX_BUILDER_BOOST_FACTOR;
|
|
150
|
+
const bestIsMaxBoost = best.boostFactor === MAX_BUILDER_BOOST_FACTOR;
|
|
151
|
+
if (candidateIsMaxBoost !== bestIsMaxBoost) {
|
|
152
|
+
if (candidateIsMaxBoost) {
|
|
153
|
+
best = candidate;
|
|
154
|
+
}
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const candidateValue = boostedValue(candidate);
|
|
158
|
+
const bestValue = boostedValue(best);
|
|
159
|
+
if (candidateValue > bestValue) {
|
|
160
|
+
best = candidate;
|
|
161
|
+
} else if (
|
|
162
|
+
candidateValue === bestValue &&
|
|
163
|
+
// A tie prefers a builder api bid over the p2p bid, and the earlier received bid otherwise
|
|
164
|
+
(best.url === undefined || (candidate.url !== undefined && candidate.receivedMs < best.receivedMs))
|
|
165
|
+
) {
|
|
166
|
+
best = candidate;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return best;
|
|
170
|
+
}
|
|
115
171
|
|
|
116
172
|
type ProduceBlockContentsRes = {executionPayloadValue: Wei; consensusBlockValue: Wei} & {
|
|
117
173
|
data: BlockContents;
|
|
@@ -857,7 +913,7 @@ export function getValidatorApi(
|
|
|
857
913
|
feeRecipient,
|
|
858
914
|
strictFeeRecipientCheck,
|
|
859
915
|
includePayload,
|
|
860
|
-
|
|
916
|
+
builderConfig,
|
|
861
917
|
}) {
|
|
862
918
|
const fork = config.getForkName(slot);
|
|
863
919
|
|
|
@@ -865,7 +921,7 @@ export function getValidatorApi(
|
|
|
865
921
|
throw new ApiError(400, `produceBlockV4 not supported for pre-gloas fork=${fork}`);
|
|
866
922
|
}
|
|
867
923
|
|
|
868
|
-
builderBoostFactor = builderBoostFactor
|
|
924
|
+
const builderBoostFactor = builderConfig.builderBoostFactor;
|
|
869
925
|
if (builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) {
|
|
870
926
|
throw new ApiError(400, `Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR`);
|
|
871
927
|
}
|
|
@@ -892,32 +948,122 @@ export function getValidatorApi(
|
|
|
892
948
|
})
|
|
893
949
|
);
|
|
894
950
|
|
|
895
|
-
// TODO GLOAS: add external builder api support when it is implemented
|
|
896
951
|
const isBuildingOnFull = chain.forkChoice.shouldBuildOnFull(parentBlock, slot);
|
|
897
952
|
const bidParentBlockHash = isBuildingOnFull ? parentBlock.executionPayloadBlockHash : parentBlock.parentBlockHash;
|
|
953
|
+
// Post-gloas every proposal parent has an execution payload hash
|
|
954
|
+
if (bidParentBlockHash === null) {
|
|
955
|
+
throw new ApiError(500, `Unknown parent block hash for proposal parent ${parentBlockRootHex}`);
|
|
956
|
+
}
|
|
898
957
|
const circuitBreakerActive = chain.builderCircuitBreaker.isActive(slot, parentBlock);
|
|
899
|
-
// Keep a builder bid as fallback unless the circuit breaker is active
|
|
900
|
-
const builderBid = circuitBreakerActive
|
|
901
|
-
? null
|
|
902
|
-
: chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
|
|
903
958
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
959
|
+
// Fire builder API bid requests while the local payload is built, one request per entry.
|
|
960
|
+
// Any entry failure yields no bid and never fails block production.
|
|
961
|
+
let builderApiBidsPromise: Promise<BuilderApiBid[]> = Promise.resolve([]);
|
|
962
|
+
if (builderConfig.builders.length > 0 && !circuitBreakerActive) {
|
|
963
|
+
try {
|
|
964
|
+
const proposerIndex = chain.getHeadState().getBeaconProposer(slot);
|
|
965
|
+
const proposerPubkey = chain.pubkeyCache.getOrThrow(proposerIndex).toBytes();
|
|
966
|
+
builderApiBidsPromise = chain.builderApiClient.getExecutionPayloadBids(
|
|
967
|
+
builderConfig.builders,
|
|
968
|
+
slot,
|
|
969
|
+
fromHex(bidParentBlockHash),
|
|
970
|
+
parentBlockRoot,
|
|
971
|
+
proposerPubkey
|
|
972
|
+
);
|
|
973
|
+
} catch (e) {
|
|
974
|
+
logger.warn("Unable to request builder API bids", {slot}, e as Error);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// A builder bid is expected if builders are configured or a p2p bid was already received.
|
|
979
|
+
// Used by the censorship override which may run before the bid deadline
|
|
980
|
+
const builderBidExpected =
|
|
981
|
+
builderConfig.builders.length > 0 ||
|
|
982
|
+
(!circuitBreakerActive &&
|
|
983
|
+
chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex) !== null);
|
|
984
|
+
|
|
985
|
+
// Select the p2p bid once builders had time to bid up, matching the deadline advertised
|
|
986
|
+
// on builder API bid requests, unless the circuit breaker is active
|
|
987
|
+
const p2pBidPromise: Promise<PooledExecutionPayloadBid | null> = circuitBreakerActive
|
|
988
|
+
? Promise.resolve(null)
|
|
989
|
+
: sleep(Math.max(0, BUILDER_BID_DEADLINE_MS - chain.clock.msFromSlot(slot))).then(() => {
|
|
990
|
+
const p2pBid = chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
|
|
991
|
+
// Discard p2p bids below the proposer's configured floor on the total payment.
|
|
992
|
+
// A p2p bid's total is just its value since gossip validation enforces executionPayment=0.
|
|
993
|
+
if (p2pBid !== null && BigInt(p2pBid.signedBid.message.value) < builderConfig.minBid) {
|
|
994
|
+
logger.info("Best p2p bid below configured minimum", {
|
|
995
|
+
slot,
|
|
996
|
+
bidValue: prettyGweiToEth(p2pBid.signedBid.message.value),
|
|
997
|
+
minBid: prettyGweiToEth(builderConfig.minBid),
|
|
998
|
+
});
|
|
999
|
+
return null;
|
|
918
1000
|
}
|
|
919
|
-
|
|
920
|
-
|
|
1001
|
+
return p2pBid;
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
// Candidates are ranked by their boosted counted total payment, the p2p bid is governed
|
|
1005
|
+
// by the top-level factors and each builder API bid by its own entry. Ties prefer the
|
|
1006
|
+
// earliest received builder API bid, so the signed block can be routed back to its
|
|
1007
|
+
// builder directly.
|
|
1008
|
+
const bestBidPromise: Promise<BidCandidate | null> = (async () => {
|
|
1009
|
+
const [builderApiBids, p2pBid] = await Promise.all([builderApiBidsPromise, p2pBidPromise]);
|
|
1010
|
+
let parentExecutionRequestsPromise: Promise<gloas.ExecutionRequests> | null = null;
|
|
1011
|
+
|
|
1012
|
+
const candidates = (
|
|
1013
|
+
await Promise.all(
|
|
1014
|
+
builderApiBids.map(async ({url, entry, signedBid, receivedMs}): Promise<BidCandidate | null> => {
|
|
1015
|
+
try {
|
|
1016
|
+
await validateBuilderApiExecutionPayloadBid(chain, signedBid, {
|
|
1017
|
+
slot,
|
|
1018
|
+
parentBlock,
|
|
1019
|
+
parentBlockHash: bidParentBlockHash,
|
|
1020
|
+
parentBlockRoot: parentBlockRootHex,
|
|
1021
|
+
entry,
|
|
1022
|
+
getParentExecutionRequests: () => {
|
|
1023
|
+
parentExecutionRequestsPromise ??= chain.getParentExecutionRequests(parentSlot, parentBlockRootHex);
|
|
1024
|
+
return parentExecutionRequestsPromise;
|
|
1025
|
+
},
|
|
1026
|
+
});
|
|
1027
|
+
return {
|
|
1028
|
+
signedBid,
|
|
1029
|
+
totalGwei: getBuilderBidTotalGwei(signedBid.message, entry.maxExecutionPayment),
|
|
1030
|
+
boostFactor: entry.builderBoostFactor,
|
|
1031
|
+
url,
|
|
1032
|
+
receivedMs,
|
|
1033
|
+
};
|
|
1034
|
+
} catch (e) {
|
|
1035
|
+
metrics?.builderApi.bidsDiscarded.inc();
|
|
1036
|
+
logger.warn("Ignoring invalid builder API bid", {slot, builder: toPrintableUrl(url)}, e as Error);
|
|
1037
|
+
return null;
|
|
1038
|
+
}
|
|
1039
|
+
})
|
|
1040
|
+
)
|
|
1041
|
+
).filter((candidate): candidate is BidCandidate => candidate !== null);
|
|
1042
|
+
|
|
1043
|
+
if (p2pBid !== null) {
|
|
1044
|
+
candidates.push({
|
|
1045
|
+
signedBid: p2pBid.signedBid,
|
|
1046
|
+
totalGwei: BigInt(p2pBid.signedBid.message.value),
|
|
1047
|
+
boostFactor: builderConfig.builderBoostFactor,
|
|
1048
|
+
receivedMs: p2pBid.receivedMs,
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
const best = selectBestBid(candidates);
|
|
1053
|
+
if (candidates.length > 0) {
|
|
1054
|
+
logger.debug("Ranked builder bid candidates", {
|
|
1055
|
+
slot,
|
|
1056
|
+
candidates: candidates
|
|
1057
|
+
.map(
|
|
1058
|
+
(candidate) =>
|
|
1059
|
+
`${candidate.url ?? "p2p"}:total=${prettyGweiToEth(candidate.totalGwei)}:boost=${candidate.boostFactor}:received=${candidate.receivedMs}ms`
|
|
1060
|
+
)
|
|
1061
|
+
.join(","),
|
|
1062
|
+
bidSource: best?.url ?? "p2p",
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
return best;
|
|
1066
|
+
})();
|
|
921
1067
|
|
|
922
1068
|
const commonBlockBodyPromise = chain.produceCommonBlockBody({
|
|
923
1069
|
slot,
|
|
@@ -937,9 +1083,6 @@ export function getValidatorApi(
|
|
|
937
1083
|
};
|
|
938
1084
|
|
|
939
1085
|
metrics?.blockProductionRequests.inc({source: ProducedBlockSource.engine});
|
|
940
|
-
if (builderBid !== null) {
|
|
941
|
-
metrics?.blockProductionRequests.inc({source: ProducedBlockSource.builder});
|
|
942
|
-
}
|
|
943
1086
|
|
|
944
1087
|
const timed = <T>(source: ProducedBlockSource, fn: () => Promise<T>): Promise<T> => {
|
|
945
1088
|
const t = metrics?.blockProductionTime.startTimer();
|
|
@@ -956,19 +1099,25 @@ export function getValidatorApi(
|
|
|
956
1099
|
const enginePromise: ReturnType<typeof chain.produceBlock> = timed(ProducedBlockSource.engine, () =>
|
|
957
1100
|
chain.produceBlock(baseAttrs)
|
|
958
1101
|
).then((engineBlock) => {
|
|
959
|
-
// No need to wait for the bid block if the engine block will always be selected
|
|
960
|
-
// suspected builder censorship or
|
|
961
|
-
|
|
1102
|
+
// No need to wait for the bid block if the engine block will always be selected, either
|
|
1103
|
+
// due to suspected builder censorship, or because no builders are configured and the
|
|
1104
|
+
// boost factor of 0 always prefers the local block over p2p bids
|
|
1105
|
+
if (engineBlock.shouldOverrideBuilder || (builderConfig.builders.length === 0 && builderBoostFactor === 0n)) {
|
|
962
1106
|
controller.abort();
|
|
963
1107
|
}
|
|
964
1108
|
return engineBlock;
|
|
965
1109
|
});
|
|
966
|
-
const
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1110
|
+
const bidBlockPromise: ReturnType<typeof chain.produceBlock> = bestBidPromise.then((candidate) => {
|
|
1111
|
+
if (candidate === null) {
|
|
1112
|
+
throw new Error(NO_BID_AVAILABLE);
|
|
1113
|
+
}
|
|
1114
|
+
metrics?.blockProductionRequests.inc({source: ProducedBlockSource.builder});
|
|
1115
|
+
return timed(ProducedBlockSource.builder, () =>
|
|
1116
|
+
chain.produceBlock({...baseAttrs, builderBid: candidate.signedBid})
|
|
1117
|
+
);
|
|
1118
|
+
});
|
|
970
1119
|
|
|
971
|
-
const [engineResult,
|
|
1120
|
+
const [engineResult, bidBlockResult] = await resolveOrRacePromises([enginePromise, bidBlockPromise], {
|
|
972
1121
|
resolveTimeoutMs: cutoffMs,
|
|
973
1122
|
raceTimeoutMs: BLOCK_PRODUCTION_RACE_TIMEOUT_MS,
|
|
974
1123
|
signal: controller.signal,
|
|
@@ -977,29 +1126,74 @@ export function getValidatorApi(
|
|
|
977
1126
|
let bestResult: typeof engineResult | null = null;
|
|
978
1127
|
let source: ProducedBlockSource = ProducedBlockSource.engine;
|
|
979
1128
|
|
|
1129
|
+
// Resolved instantly whenever the bid branch produced a block
|
|
1130
|
+
const bestBid = bidBlockResult.status === "fulfilled" ? await bestBidPromise : null;
|
|
1131
|
+
|
|
1132
|
+
const logCtx = {
|
|
1133
|
+
slot,
|
|
1134
|
+
parentSlot,
|
|
1135
|
+
parentBlockRoot: parentBlockRootHex,
|
|
1136
|
+
parentBlockHash: parentBlock.executionPayloadBlockHash,
|
|
1137
|
+
fork,
|
|
1138
|
+
builderBoostFactor,
|
|
1139
|
+
strictFeeRecipientCheck,
|
|
1140
|
+
circuitBreakerActive,
|
|
1141
|
+
builderEntries: builderConfig.builders.length,
|
|
1142
|
+
...(bestBid !== null
|
|
1143
|
+
? {
|
|
1144
|
+
bidSource: bestBid.url !== undefined ? toPrintableUrl(bestBid.url) : "p2p",
|
|
1145
|
+
bidValue: prettyGweiToEth(bestBid.signedBid.message.value),
|
|
1146
|
+
bidExecutionPayment: prettyGweiToEth(bestBid.signedBid.message.executionPayment),
|
|
1147
|
+
// The full bid total and the counted total used during bid selection
|
|
1148
|
+
bidTotal: prettyGweiToEth(
|
|
1149
|
+
BigInt(bestBid.signedBid.message.value) + bestBid.signedBid.message.executionPayment
|
|
1150
|
+
),
|
|
1151
|
+
bidCountedTotal: prettyGweiToEth(bestBid.totalGwei),
|
|
1152
|
+
bidBoostFactor: bestBid.boostFactor,
|
|
1153
|
+
builderIndex: bestBid.signedBid.message.builderIndex,
|
|
1154
|
+
bidBlockHash: toRootHex(bestBid.signedBid.message.blockHash),
|
|
1155
|
+
bidReceivedMs: bestBid.receivedMs,
|
|
1156
|
+
}
|
|
1157
|
+
: {}),
|
|
1158
|
+
};
|
|
1159
|
+
|
|
980
1160
|
// handle shouldOverrideBuilder separately
|
|
981
|
-
if (
|
|
1161
|
+
if (
|
|
1162
|
+
engineResult.status === "fulfilled" &&
|
|
1163
|
+
engineResult.value.shouldOverrideBuilder &&
|
|
1164
|
+
(builderBidExpected || bidBlockResult.status === "fulfilled")
|
|
1165
|
+
) {
|
|
982
1166
|
source = ProducedBlockSource.engine;
|
|
983
1167
|
bestResult = engineResult;
|
|
984
1168
|
metrics?.blockProductionSelectionResults.inc({
|
|
985
1169
|
source: ProducedBlockSource.engine,
|
|
986
1170
|
reason: EngineBlockSelectionReason.BuilderCensorship,
|
|
987
1171
|
});
|
|
988
|
-
logger.warn("Selected local block: censorship suspected in builder bid",
|
|
989
|
-
|
|
1172
|
+
logger.warn("Selected local block: censorship suspected in builder bid", {
|
|
1173
|
+
...logCtx,
|
|
1174
|
+
durationMs: engineResult.durationMs,
|
|
1175
|
+
...getBlockValueLogInfo(engineResult.value),
|
|
1176
|
+
});
|
|
1177
|
+
} else if (engineResult.status === "fulfilled" && bidBlockResult.status === "fulfilled") {
|
|
990
1178
|
const result = selectBlockProductionSourceByBoostFactor({
|
|
991
|
-
builderBoostFactor,
|
|
1179
|
+
builderBoostFactor: bestBid?.boostFactor ?? builderBoostFactor,
|
|
992
1180
|
engineExecutionPayloadValue: engineResult.value.executionPayloadValue,
|
|
993
|
-
// The bid
|
|
994
|
-
builderExecutionPayloadValue:
|
|
1181
|
+
// The bid total payment is its value plus its counted executionPayment, in Gwei
|
|
1182
|
+
builderExecutionPayloadValue: (bestBid?.totalGwei ?? 0n) * GWEI_TO_WEI,
|
|
995
1183
|
});
|
|
996
1184
|
source = result.source;
|
|
997
1185
|
metrics?.blockProductionSelectionResults.inc(result);
|
|
998
|
-
logger.info(`Selected ${source} block`, {
|
|
999
|
-
|
|
1000
|
-
|
|
1186
|
+
logger.info(`Selected ${source} block`, {
|
|
1187
|
+
reason: result.reason,
|
|
1188
|
+
...logCtx,
|
|
1189
|
+
engineDurationMs: engineResult.durationMs,
|
|
1190
|
+
...getBlockValueLogInfo(engineResult.value, ProducedBlockSource.engine),
|
|
1191
|
+
builderDurationMs: bidBlockResult.durationMs,
|
|
1192
|
+
});
|
|
1193
|
+
bestResult = source === ProducedBlockSource.builder ? bidBlockResult : engineResult;
|
|
1194
|
+
} else if (bidBlockResult.status === "fulfilled") {
|
|
1001
1195
|
source = ProducedBlockSource.builder;
|
|
1002
|
-
bestResult =
|
|
1196
|
+
bestResult = bidBlockResult;
|
|
1003
1197
|
const reason =
|
|
1004
1198
|
engineResult.status === "pending"
|
|
1005
1199
|
? BuilderBlockSelectionReason.EnginePending
|
|
@@ -1008,28 +1202,32 @@ export function getValidatorApi(
|
|
|
1008
1202
|
logger.info("Selected builder bid block: no local block produced", {
|
|
1009
1203
|
reason,
|
|
1010
1204
|
...logCtx,
|
|
1205
|
+
durationMs: bidBlockResult.durationMs,
|
|
1206
|
+
...getBlockValueLogInfo(bidBlockResult.value),
|
|
1011
1207
|
error: engineResult.status === "rejected" ? (engineResult.reason as Error).message : undefined,
|
|
1012
1208
|
});
|
|
1013
1209
|
} else if (engineResult.status === "fulfilled") {
|
|
1014
1210
|
source = ProducedBlockSource.engine;
|
|
1015
1211
|
bestResult = engineResult;
|
|
1016
1212
|
const reason =
|
|
1017
|
-
|
|
1213
|
+
bidBlockResult.status === "rejected" && (bidBlockResult.reason as Error).message === NO_BID_AVAILABLE
|
|
1018
1214
|
? EngineBlockSelectionReason.BuilderNoBid
|
|
1019
|
-
:
|
|
1215
|
+
: bidBlockResult.status === "pending"
|
|
1020
1216
|
? EngineBlockSelectionReason.BuilderPending
|
|
1021
1217
|
: EngineBlockSelectionReason.BuilderError;
|
|
1022
1218
|
metrics?.blockProductionSelectionResults.inc({source: ProducedBlockSource.engine, reason});
|
|
1023
1219
|
logger.info("Selected local block: no builder bid block produced", {
|
|
1024
1220
|
reason,
|
|
1025
1221
|
...logCtx,
|
|
1026
|
-
|
|
1222
|
+
durationMs: engineResult.durationMs,
|
|
1223
|
+
...getBlockValueLogInfo(engineResult.value),
|
|
1224
|
+
error: bidBlockResult.status === "rejected" ? (bidBlockResult.reason as Error).message : undefined,
|
|
1027
1225
|
});
|
|
1028
1226
|
}
|
|
1029
1227
|
|
|
1030
1228
|
if (bestResult === null || bestResult.status !== "fulfilled") {
|
|
1031
1229
|
const engineReason = engineResult.status === "rejected" ? engineResult.reason : engineResult.status;
|
|
1032
|
-
const bidReason =
|
|
1230
|
+
const bidReason = bidBlockResult.status === "rejected" ? bidBlockResult.reason : bidBlockResult.status;
|
|
1033
1231
|
logger.error("Block production failed", {
|
|
1034
1232
|
...logCtx,
|
|
1035
1233
|
engineReason: String(engineReason),
|
|
@@ -1093,7 +1291,13 @@ export function getValidatorApi(
|
|
|
1093
1291
|
|
|
1094
1292
|
return {
|
|
1095
1293
|
data: block as gloas.BeaconBlock,
|
|
1096
|
-
meta: {
|
|
1294
|
+
meta: {
|
|
1295
|
+
version: fork,
|
|
1296
|
+
consensusBlockValue,
|
|
1297
|
+
executionPayloadValue,
|
|
1298
|
+
executionPayloadIncluded: false,
|
|
1299
|
+
builderUrl: source === ProducedBlockSource.builder ? bestBid?.url : undefined,
|
|
1300
|
+
},
|
|
1097
1301
|
};
|
|
1098
1302
|
},
|
|
1099
1303
|
|
|
@@ -1877,6 +2081,43 @@ export function getValidatorApi(
|
|
|
1877
2081
|
}
|
|
1878
2082
|
},
|
|
1879
2083
|
|
|
2084
|
+
async submitBuilderPreferences({builderPreferences}) {
|
|
2085
|
+
const failures: FailureList = [];
|
|
2086
|
+
|
|
2087
|
+
await Promise.all(
|
|
2088
|
+
builderPreferences.map(async (entry, i) => {
|
|
2089
|
+
let builder = Buffer.from(entry.url).toString("utf8");
|
|
2090
|
+
try {
|
|
2091
|
+
const url = decodeBuilderUrl(entry.url);
|
|
2092
|
+
builder = toPrintableUrl(url);
|
|
2093
|
+
const proposerIndex = chain.getHeadState().getBeaconProposer(entry.auth.message.slot);
|
|
2094
|
+
const expectedProposerPubkey = chain.pubkeyCache.getOrThrow(proposerIndex).toBytes();
|
|
2095
|
+
if (!byteArrayEquals(entry.proposerPubkey, expectedProposerPubkey)) {
|
|
2096
|
+
throw new ApiError(
|
|
2097
|
+
400,
|
|
2098
|
+
`Invalid proposer pubkey for builder preferences slot=${entry.auth.message.slot}`
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
await chain.builderApiClient.submitBuilderPreferences(url, entry.proposerPubkey, {
|
|
2102
|
+
preferences: {maxExecutionPayment: entry.maxExecutionPayment},
|
|
2103
|
+
auth: entry.auth,
|
|
2104
|
+
});
|
|
2105
|
+
} catch (e) {
|
|
2106
|
+
failures.push({index: i, message: (e as Error).message});
|
|
2107
|
+
logger.verbose(
|
|
2108
|
+
`Error on submitBuilderPreferences [${i}]`,
|
|
2109
|
+
{slot: entry.auth.message.slot, builder},
|
|
2110
|
+
e as Error
|
|
2111
|
+
);
|
|
2112
|
+
}
|
|
2113
|
+
})
|
|
2114
|
+
);
|
|
2115
|
+
|
|
2116
|
+
if (failures.length > 0) {
|
|
2117
|
+
throw new IndexedError("Error submitting builder preferences", failures);
|
|
2118
|
+
}
|
|
2119
|
+
},
|
|
2120
|
+
|
|
1880
2121
|
async getExecutionPayloadEnvelope({slot, beaconBlockRoot}) {
|
|
1881
2122
|
const fork = config.getForkName(slot);
|
|
1882
2123
|
|
|
@@ -89,7 +89,7 @@ export function selectBlockProductionSourceByBoostFactor({
|
|
|
89
89
|
return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BuilderPreferred};
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
if (engineExecutionPayloadValue >=
|
|
92
|
+
if (engineExecutionPayloadValue * 100n >= builderExecutionPayloadValue * builderBoostFactor) {
|
|
93
93
|
return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.BlockValue};
|
|
94
94
|
}
|
|
95
95
|
|
package/src/api/rest/base.ts
CHANGED
|
@@ -104,6 +104,13 @@ export class RestApiServer {
|
|
|
104
104
|
|
|
105
105
|
// To parse our ApiError -> statusCode
|
|
106
106
|
server.setErrorHandler<FastifyError | Error>((err, _req, res) => {
|
|
107
|
+
if (res.raw.headersSent) {
|
|
108
|
+
// A status code can no longer be written, e.g. if a long-lived SSE stream failed mid-flight.
|
|
109
|
+
// End the response instead, else the socket is left open and the client never notices.
|
|
110
|
+
if (!res.raw.writableEnded && !res.raw.destroyed) res.raw.end();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
107
114
|
const stacktraces = opts.stacktraces ? err.stack?.split("\n") : undefined;
|
|
108
115
|
if ("validation" in err && err.validation) {
|
|
109
116
|
const {instancePath = "unknown", message} = err.validation?.[0] ?? {};
|
|
@@ -192,7 +192,7 @@ export class ArchiveStore {
|
|
|
192
192
|
|
|
193
193
|
private onCheckpoint = (): void => {
|
|
194
194
|
const headStateRoot = this.chain.forkChoice.getHead().stateRoot;
|
|
195
|
-
this.chain.regen.
|
|
195
|
+
this.chain.regen.onCheckpoint(
|
|
196
196
|
this.chain.forkChoice.getFinalizedCheckpoint().epoch,
|
|
197
197
|
this.chain.forkChoice.getJustifiedCheckpoint().epoch,
|
|
198
198
|
headStateRoot
|
|
@@ -58,11 +58,12 @@ export type PayloadErrorType =
|
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
export class PayloadError extends Error {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
constructor(
|
|
62
|
+
readonly payloadInput: PayloadEnvelopeInput,
|
|
63
|
+
readonly type: PayloadErrorType,
|
|
64
|
+
message?: string
|
|
65
|
+
) {
|
|
64
66
|
super(message ?? type.code);
|
|
65
|
-
this.type = type;
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -125,7 +126,7 @@ export async function importExecutionPayload(
|
|
|
125
126
|
// 2. Get ProtoBlock for parent root lookup
|
|
126
127
|
const protoBlock = this.forkChoice.getBlockHexDefaultStatus(blockRootHex);
|
|
127
128
|
if (!protoBlock) {
|
|
128
|
-
throw new PayloadError({
|
|
129
|
+
throw new PayloadError(payloadInput, {
|
|
129
130
|
code: PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE,
|
|
130
131
|
blockRootHex,
|
|
131
132
|
});
|
|
@@ -140,13 +141,13 @@ export async function importExecutionPayload(
|
|
|
140
141
|
);
|
|
141
142
|
|
|
142
143
|
if (blockState == null) {
|
|
143
|
-
throw new PayloadError({
|
|
144
|
+
throw new PayloadError(payloadInput, {
|
|
144
145
|
code: PayloadErrorCode.MISS_BLOCK_STATE,
|
|
145
146
|
blockRootHex: protoBlock.blockRoot,
|
|
146
147
|
});
|
|
147
148
|
}
|
|
148
149
|
if (!isStatePostGloas(blockState)) {
|
|
149
|
-
throw new PayloadError({
|
|
150
|
+
throw new PayloadError(payloadInput, {
|
|
150
151
|
code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
|
|
151
152
|
message: `Expected gloas+ state for payload import, got fork=${blockState.forkName}`,
|
|
152
153
|
});
|
|
@@ -161,6 +162,7 @@ export async function importExecutionPayload(
|
|
|
161
162
|
});
|
|
162
163
|
} catch (e) {
|
|
163
164
|
throw new PayloadError(
|
|
165
|
+
payloadInput,
|
|
164
166
|
{
|
|
165
167
|
code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
|
|
166
168
|
message: (e as Error).message,
|
|
@@ -184,7 +186,6 @@ export async function importExecutionPayload(
|
|
|
184
186
|
: verifyExecutionPayloadEnvelopeSignature(
|
|
185
187
|
this.config,
|
|
186
188
|
blockState,
|
|
187
|
-
this.pubkeyCache,
|
|
188
189
|
signedEnvelope,
|
|
189
190
|
payloadInput.proposerIndex,
|
|
190
191
|
this.bls
|
|
@@ -193,7 +194,7 @@ export async function importExecutionPayload(
|
|
|
193
194
|
|
|
194
195
|
// 4b. Check signature verification result
|
|
195
196
|
if (!signatureValid) {
|
|
196
|
-
throw new PayloadError({code: PayloadErrorCode.INVALID_SIGNATURE});
|
|
197
|
+
throw new PayloadError(payloadInput, {code: PayloadErrorCode.INVALID_SIGNATURE});
|
|
197
198
|
}
|
|
198
199
|
|
|
199
200
|
// 4c. Handle EL response
|
|
@@ -202,7 +203,7 @@ export async function importExecutionPayload(
|
|
|
202
203
|
break;
|
|
203
204
|
|
|
204
205
|
case ExecutionPayloadStatus.INVALID:
|
|
205
|
-
throw new PayloadError({
|
|
206
|
+
throw new PayloadError(payloadInput, {
|
|
206
207
|
code: PayloadErrorCode.EXECUTION_ENGINE_INVALID,
|
|
207
208
|
execStatus: execResult.status,
|
|
208
209
|
errorMessage: execResult.validationError ?? "",
|
|
@@ -215,7 +216,7 @@ export async function importExecutionPayload(
|
|
|
215
216
|
case ExecutionPayloadStatus.INVALID_BLOCK_HASH:
|
|
216
217
|
case ExecutionPayloadStatus.ELERROR:
|
|
217
218
|
case ExecutionPayloadStatus.UNAVAILABLE:
|
|
218
|
-
throw new PayloadError({
|
|
219
|
+
throw new PayloadError(payloadInput, {
|
|
219
220
|
code: PayloadErrorCode.EXECUTION_ENGINE_ERROR,
|
|
220
221
|
execStatus: execResult.status,
|
|
221
222
|
errorMessage: execResult.validationError ?? "",
|
|
@@ -8,7 +8,7 @@ import {BlockError, BlockErrorCode, isBlockErrorAborted} from "../errors/index.j
|
|
|
8
8
|
import {BlockProcessOpts} from "../options.js";
|
|
9
9
|
import {IBlockInput} from "./blockInput/types.js";
|
|
10
10
|
import {importBlock} from "./importBlock.js";
|
|
11
|
-
import {importExecutionPayload} from "./importExecutionPayload.js";
|
|
11
|
+
import {PayloadError, importExecutionPayload} from "./importExecutionPayload.js";
|
|
12
12
|
import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
13
13
|
import {FullyVerifiedBlock, ImportBlockOpts} from "./types.js";
|
|
14
14
|
import {assertLinearChainSegment} from "./utils/chainSegment.js";
|
|
@@ -143,17 +143,17 @@ export async function processBlocks(
|
|
|
143
143
|
await importBlock.call(this, fullyVerifiedBlock, opts);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
// PayloadEnvelopeInput is shared and may receive an envelope after the DA snapshot was taken.
|
|
147
|
+
const payloadDA = payloadDAStatuses.get(slot);
|
|
148
|
+
if (payloadDA !== undefined) {
|
|
149
|
+
const payloadInput = payloadEnvelopes?.get(slot);
|
|
150
|
+
if (payloadInput === undefined) {
|
|
151
|
+
throw new Error(`Missing payload input for slot ${slot} after DA verification`);
|
|
152
|
+
}
|
|
148
153
|
if (!payloadInput.isComplete()) {
|
|
149
154
|
// we validated DA before reaching this
|
|
150
155
|
throw new Error(`Payload envelope for slot ${slot} not complete after DA verification`);
|
|
151
156
|
}
|
|
152
|
-
// we already awaited DA in verifyBlocksInEpoch for this segment
|
|
153
|
-
const payloadDA = payloadDAStatuses.get(slot);
|
|
154
|
-
if (payloadDA === undefined) {
|
|
155
|
-
throw new Error(`Missing payload DA status for slot ${slot}`);
|
|
156
|
-
}
|
|
157
157
|
await importExecutionPayload.call(this, payloadInput, payloadDA, {validSignature: false});
|
|
158
158
|
}
|
|
159
159
|
|
|
@@ -164,13 +164,21 @@ export async function processBlocks(
|
|
|
164
164
|
return; // Ignore
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
// above functions should only throw BlockError
|
|
168
|
-
const err =
|
|
167
|
+
// above functions should only throw BlockError, or PayloadError from the gloas payload import
|
|
168
|
+
const err = getBlockOrPayloadError(e, blocks[0].getBlock());
|
|
169
169
|
|
|
170
170
|
// TODO: De-duplicate with logic above
|
|
171
171
|
// ChainEvent.errorBlock
|
|
172
|
-
if (!(err instanceof BlockError)) {
|
|
173
|
-
this.logger.debug("
|
|
172
|
+
if (!(err instanceof BlockError) && !(err instanceof PayloadError)) {
|
|
173
|
+
this.logger.debug("Neither BlockError nor PayloadError received", {}, err);
|
|
174
|
+
} else if (err instanceof PayloadError) {
|
|
175
|
+
if (!opts.disableOnBlockError) {
|
|
176
|
+
this.logger.debug(
|
|
177
|
+
"Payload error",
|
|
178
|
+
{slot: err.payloadInput.slot, blockRoot: err.payloadInput.blockRootHex},
|
|
179
|
+
err
|
|
180
|
+
);
|
|
181
|
+
}
|
|
174
182
|
} else if (!opts.disableOnBlockError) {
|
|
175
183
|
this.logger.debug("Block error", {slot: err.signedBlock.message.slot}, err);
|
|
176
184
|
|
|
@@ -201,11 +209,15 @@ export async function processBlocks(
|
|
|
201
209
|
}
|
|
202
210
|
}
|
|
203
211
|
|
|
204
|
-
function
|
|
212
|
+
function getBlockOrPayloadError(e: unknown, block: SignedBeaconBlock): BlockError | PayloadError {
|
|
205
213
|
if (e instanceof BlockError) {
|
|
206
214
|
return e;
|
|
207
215
|
}
|
|
208
216
|
|
|
217
|
+
if (e instanceof PayloadError) {
|
|
218
|
+
return e;
|
|
219
|
+
}
|
|
220
|
+
|
|
209
221
|
if (e instanceof Error) {
|
|
210
222
|
const blockError = new BlockError(block, {code: BlockErrorCode.BEACON_CHAIN_ERROR, error: e});
|
|
211
223
|
blockError.stack = e.stack;
|