@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
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Max distinct peers tracked per unknown block/payload root.
|
|
3
|
+
* Normally we have 8 mesh peers per topic, and multi topics may point to the same root.
|
|
4
|
+
* Having 32 peers per root seems enough to search for missing blocks/payloads.
|
|
5
|
+
**/
|
|
6
|
+
export const MAX_PEERS_PER_ROOT = 32;
|
|
@@ -196,7 +196,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
196
196
|
forkName: fork,
|
|
197
197
|
sampledColumns: chain.custodyConfig.sampledColumns,
|
|
198
198
|
custodyColumns: chain.custodyConfig.custodyColumns,
|
|
199
|
-
|
|
199
|
+
seenTimestampSec,
|
|
200
|
+
source: PayloadEnvelopeInputSource.gossip,
|
|
200
201
|
});
|
|
201
202
|
}
|
|
202
203
|
|
|
@@ -640,6 +641,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
640
641
|
metrics?.gossipBlock.elapsedTimeTillProcessed.observe(delaySec);
|
|
641
642
|
|
|
642
643
|
if (isForkPostGloas(blockInput.forkName)) {
|
|
644
|
+
// we should have the payloadInput in the seen cache so no need getOrReload() here
|
|
643
645
|
const payloadInput = chain.seenPayloadEnvelopeInputCache.get(blockInput.blockRootHex);
|
|
644
646
|
// This payloadInput should have been created just after gossip validation
|
|
645
647
|
if (!payloadInput) {
|
|
@@ -1189,6 +1191,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1189
1191
|
chain.validatorMonitor?.registerExecutionPayloadEnvelope(OpSource.gossip, delaySec, signedEnvelope);
|
|
1190
1192
|
|
|
1191
1193
|
const blockRootHex = toRootHex(envelope.beaconBlockRoot);
|
|
1194
|
+
// a gossip payload cannot be `MAX_PAYLOAD_ENVELOPE_INPUT_CACHE_SIZE` slots after the block
|
|
1195
|
+
// otherwise it'll get to UnknownBlockInput flow
|
|
1192
1196
|
const payloadInput = chain.seenPayloadEnvelopeInputCache.get(blockRootHex);
|
|
1193
1197
|
|
|
1194
1198
|
if (!payloadInput) {
|
|
@@ -1302,7 +1306,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1302
1306
|
|
|
1303
1307
|
// Handle valid payload bid by storing in a bid pool
|
|
1304
1308
|
try {
|
|
1305
|
-
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid);
|
|
1309
|
+
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid, Math.floor(elapsedSec * 1000));
|
|
1306
1310
|
metrics?.opPool.executionPayloadBidPool.gossipInsertOutcome.inc({insertOutcome});
|
|
1307
1311
|
} catch (e) {
|
|
1308
1312
|
logger.error("Error adding to executionPayloadBid pool", {}, e as Error);
|
|
@@ -86,7 +86,6 @@ export class IndexedGossipQueueMinSize<T extends {indexed?: string; queueAddedMs
|
|
|
86
86
|
const now = Date.now();
|
|
87
87
|
// here we mutate item, which is used for gossip validation later
|
|
88
88
|
item.indexed = key;
|
|
89
|
-
item.queueAddedMs = now;
|
|
90
89
|
let queueItem = this.indexedItems.get(key);
|
|
91
90
|
if (queueItem == null) {
|
|
92
91
|
queueItem = {firstSeenMs: now, listItems: new LinkedList<T>()};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {TopicValidatorResult} from "@libp2p/gossipsub";
|
|
1
2
|
import {routes} from "@lodestar/api";
|
|
2
3
|
import {ForkSeq} from "@lodestar/params";
|
|
3
4
|
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
GossipValidatorBatchFn,
|
|
31
32
|
GossipValidatorFn,
|
|
32
33
|
} from "../gossip/interface.js";
|
|
34
|
+
import {MAX_PEERS_PER_ROOT} from "./constants.js";
|
|
33
35
|
import {createExtractBlockSlotRootFns} from "./extractSlotRootFns.js";
|
|
34
36
|
import {GossipHandlerOpts, ValidatorFnsModules, getGossipHandlers} from "./gossipHandlers.js";
|
|
35
37
|
import {createGossipQueues} from "./gossipQueues/index.js";
|
|
@@ -191,8 +193,12 @@ export class NetworkProcessor {
|
|
|
191
193
|
// in that case PendingGossipsubMessage needs to be stored in this Map and reprocessed once the payload comes
|
|
192
194
|
private readonly awaitingMessagesByPayloadBlockRoot: MapDef<RootHex, Set<PendingGossipsubMessage>>;
|
|
193
195
|
private awaitingPayloadMessageCount = 0;
|
|
194
|
-
private unknownBlocksBySlot = new MapDef<Slot,
|
|
195
|
-
|
|
196
|
+
private unknownBlocksBySlot = new MapDef<Slot, MapDef<RootHex, Set<PeerIdStr>>>(
|
|
197
|
+
() => new MapDef<RootHex, Set<PeerIdStr>>(() => new Set())
|
|
198
|
+
);
|
|
199
|
+
private unknownEnvelopesBySlot = new MapDef<Slot, MapDef<RootHex, Set<PeerIdStr>>>(
|
|
200
|
+
() => new MapDef<RootHex, Set<PeerIdStr>>(() => new Set())
|
|
201
|
+
);
|
|
196
202
|
|
|
197
203
|
constructor(
|
|
198
204
|
modules: NetworkProcessorModules,
|
|
@@ -271,35 +277,53 @@ export class NetworkProcessor {
|
|
|
271
277
|
* Search block via `ChainEvent.unknownBlockRoot` event
|
|
272
278
|
* Slot is the message slot, which is not necessarily the same as the block's slot, but it can be used for a good prune strategy.
|
|
273
279
|
* In the rare case, if 2 messages on 2 slots search for the same root (for example beacon_attestation) we may emit the same root twice but BlockInputSync should handle it well.
|
|
280
|
+
* We forward every distinct peer that gossiped this root (not just the first) so BlockInputSync can
|
|
281
|
+
* prefer them as by-root download candidates.
|
|
274
282
|
*/
|
|
275
283
|
searchUnknownBlock({slot, root}: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
|
|
276
|
-
if (
|
|
277
|
-
this.chain.seenBlock(root) ||
|
|
278
|
-
this.awaitingMessagesByBlockRoot.has(root) ||
|
|
279
|
-
this.unknownBlocksBySlot.getOrDefault(slot).has(root)
|
|
280
|
-
) {
|
|
284
|
+
if (this.chain.seenBlock(root)) {
|
|
281
285
|
return;
|
|
282
286
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
287
|
+
const peersForRoot = this.unknownBlocksBySlot.getOrDefault(slot);
|
|
288
|
+
const alreadySearching = peersForRoot.has(root) || this.awaitingMessagesByBlockRoot.has(root);
|
|
289
|
+
const forwardedPeers = peersForRoot.getOrDefault(root);
|
|
290
|
+
|
|
291
|
+
// brand-new search always emits (peer may be undefined)
|
|
292
|
+
let shouldEmit = !alreadySearching;
|
|
293
|
+
if (peer !== undefined && !forwardedPeers.has(peer) && forwardedPeers.size < MAX_PEERS_PER_ROOT) {
|
|
294
|
+
// First time we forward THIS peer for THIS root: emit so BlockInputSync accumulates it.
|
|
295
|
+
forwardedPeers.add(peer);
|
|
296
|
+
shouldEmit = true;
|
|
297
|
+
}
|
|
298
|
+
if (shouldEmit) {
|
|
299
|
+
this.chain.emitter.emit(ChainEvent.unknownBlockRoot, {rootHex: root, peer, source});
|
|
300
|
+
}
|
|
286
301
|
}
|
|
287
302
|
|
|
288
303
|
/**
|
|
289
304
|
* Search envelope via `ChainEvent.unknownEnvelopeBlockRoot` event
|
|
290
305
|
* Slot is the message slot, which is not necessarily the same as the envelope's slot, but it can be used for a good prune strategy.
|
|
291
306
|
* In the rare case, if 2 messages on 2 slots search for the same root (for example beacon_attestation) we may emit the same root twice but BlockInputSync should handle it well.
|
|
307
|
+
* Same peer-forwarding + dedup behavior as searchUnknownBlock.
|
|
292
308
|
*/
|
|
293
309
|
searchUnknownEnvelope({slot, root}: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
|
|
294
|
-
if (
|
|
295
|
-
this.chain.seenPayloadEnvelope(root) ||
|
|
296
|
-
this.awaitingMessagesByPayloadBlockRoot.has(root) ||
|
|
297
|
-
this.unknownEnvelopesBySlot.getOrDefault(slot).has(root)
|
|
298
|
-
) {
|
|
310
|
+
if (this.chain.seenPayloadEnvelope(root)) {
|
|
299
311
|
return;
|
|
300
312
|
}
|
|
301
|
-
this.unknownEnvelopesBySlot.getOrDefault(slot)
|
|
302
|
-
|
|
313
|
+
const peersForRoot = this.unknownEnvelopesBySlot.getOrDefault(slot);
|
|
314
|
+
// capture "already searching" BEFORE getOrDefault(root) creates the entry
|
|
315
|
+
const alreadySearching = peersForRoot.has(root) || this.awaitingMessagesByPayloadBlockRoot.has(root);
|
|
316
|
+
const forwardedPeers = peersForRoot.getOrDefault(root);
|
|
317
|
+
|
|
318
|
+
let shouldEmit = !alreadySearching; // brand-new search always emits (peer may be undefined)
|
|
319
|
+
if (peer !== undefined && !forwardedPeers.has(peer) && forwardedPeers.size < MAX_PEERS_PER_ROOT) {
|
|
320
|
+
// First time we forward THIS peer for THIS root: emit so BlockInputSync accumulates it.
|
|
321
|
+
forwardedPeers.add(peer);
|
|
322
|
+
shouldEmit = true;
|
|
323
|
+
}
|
|
324
|
+
if (shouldEmit) {
|
|
325
|
+
this.chain.emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, {rootHex: root, slot, peer, source});
|
|
326
|
+
}
|
|
303
327
|
}
|
|
304
328
|
|
|
305
329
|
private onPendingGossipsubMessage = (message: PendingGossipsubMessage): void => {
|
|
@@ -537,6 +561,7 @@ export class NetworkProcessor {
|
|
|
537
561
|
|
|
538
562
|
private pushPendingGossipsubMessageToQueue(message: PendingGossipsubMessage): void {
|
|
539
563
|
const topicType = message.topic.type;
|
|
564
|
+
message.queueAddedMs = Date.now();
|
|
540
565
|
const droppedCount = this.gossipQueues[topicType].add(message);
|
|
541
566
|
if (droppedCount) {
|
|
542
567
|
// No need to report the dropped job to gossip. It will be eventually pruned from the mcache
|
|
@@ -616,7 +641,7 @@ export class NetworkProcessor {
|
|
|
616
641
|
|
|
617
642
|
for (const [slot, roots] of this.unknownBlocksBySlot) {
|
|
618
643
|
if (slot > minSlot) continue;
|
|
619
|
-
for (const rootHex of roots) {
|
|
644
|
+
for (const rootHex of roots.keys()) {
|
|
620
645
|
const gossipMessages = this.awaitingMessagesByBlockRoot.get(rootHex);
|
|
621
646
|
if (gossipMessages !== undefined) {
|
|
622
647
|
for (const message of gossipMessages) {
|
|
@@ -641,7 +666,7 @@ export class NetworkProcessor {
|
|
|
641
666
|
|
|
642
667
|
for (const [slot, roots] of this.unknownEnvelopesBySlot) {
|
|
643
668
|
if (slot > minSlot) continue;
|
|
644
|
-
for (const rootHex of roots) {
|
|
669
|
+
for (const rootHex of roots.keys()) {
|
|
645
670
|
const gossipMessages = this.awaitingMessagesByPayloadBlockRoot.get(rootHex);
|
|
646
671
|
if (gossipMessages !== undefined) {
|
|
647
672
|
for (const message of gossipMessages) {
|
|
@@ -723,12 +748,20 @@ export class NetworkProcessor {
|
|
|
723
748
|
for (const msg of messageOrArray) {
|
|
724
749
|
msg.startProcessUnixSec = nowSec;
|
|
725
750
|
if (msg.queueAddedMs !== undefined) {
|
|
726
|
-
this.metrics?.gossipValidationQueue.queueTime.observe(
|
|
751
|
+
this.metrics?.gossipValidationQueue.queueTime.observe(
|
|
752
|
+
{topic: msg.topic.type},
|
|
753
|
+
nowSec - msg.queueAddedMs / 1000
|
|
754
|
+
);
|
|
727
755
|
}
|
|
728
756
|
}
|
|
729
757
|
} else {
|
|
730
|
-
// indexed queue is not used here
|
|
731
758
|
messageOrArray.startProcessUnixSec = nowSec;
|
|
759
|
+
if (messageOrArray.queueAddedMs !== undefined) {
|
|
760
|
+
this.metrics?.gossipValidationQueue.queueTime.observe(
|
|
761
|
+
{topic: messageOrArray.topic.type},
|
|
762
|
+
nowSec - messageOrArray.queueAddedMs / 1000
|
|
763
|
+
);
|
|
764
|
+
}
|
|
732
765
|
}
|
|
733
766
|
|
|
734
767
|
const acceptanceArr = Array.isArray(messageOrArray)
|
|
@@ -741,11 +774,11 @@ export class NetworkProcessor {
|
|
|
741
774
|
];
|
|
742
775
|
|
|
743
776
|
if (Array.isArray(messageOrArray)) {
|
|
744
|
-
for (const msg of messageOrArray) {
|
|
745
|
-
this.trackJobTime(msg, messageOrArray.length);
|
|
777
|
+
for (const [i, msg] of messageOrArray.entries()) {
|
|
778
|
+
this.trackJobTime(msg, messageOrArray.length, acceptanceArr[i]);
|
|
746
779
|
}
|
|
747
780
|
} else {
|
|
748
|
-
this.trackJobTime(messageOrArray, 1);
|
|
781
|
+
this.trackJobTime(messageOrArray, 1, acceptanceArr[0]);
|
|
749
782
|
}
|
|
750
783
|
|
|
751
784
|
// Use setTimeout to yield to the macro queue
|
|
@@ -773,17 +806,21 @@ export class NetworkProcessor {
|
|
|
773
806
|
}
|
|
774
807
|
}
|
|
775
808
|
|
|
776
|
-
private trackJobTime(message: PendingGossipsubMessage, numJob: number): void {
|
|
809
|
+
private trackJobTime(message: PendingGossipsubMessage, numJob: number, acceptance: TopicValidatorResult): void {
|
|
777
810
|
if (message.startProcessUnixSec !== null) {
|
|
811
|
+
// record job wait time for all messages
|
|
778
812
|
this.metrics?.gossipValidationQueue.jobWaitTime.observe(
|
|
779
813
|
{topic: message.topic.type},
|
|
780
814
|
message.startProcessUnixSec - message.seenTimestampSec
|
|
781
815
|
);
|
|
782
|
-
//
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
816
|
+
// but only record job time for ACCEPT messages
|
|
817
|
+
if (acceptance === TopicValidatorResult.Accept) {
|
|
818
|
+
// if it takes 64ms to process 64 jobs, the average job time is 1ms
|
|
819
|
+
this.metrics?.gossipValidationQueue.jobTime.observe(
|
|
820
|
+
{topic: message.topic.type},
|
|
821
|
+
(Date.now() / 1000 - message.startProcessUnixSec) / numJob
|
|
822
|
+
);
|
|
823
|
+
}
|
|
787
824
|
}
|
|
788
825
|
}
|
|
789
826
|
|
|
@@ -44,17 +44,11 @@ export function onOutgoingReqRespError(e: RequestError, method: ReqRespMethod):
|
|
|
44
44
|
// failure, so keep the stronger penalty (Fatal for Ping, as before).
|
|
45
45
|
return method === ReqRespMethod.Ping ? PeerAction.Fatal : PeerAction.LowToleranceError;
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
case ReqRespMethod.Ping:
|
|
53
|
-
case ReqRespMethod.Status:
|
|
54
|
-
return PeerAction.HighToleranceError;
|
|
55
|
-
default:
|
|
56
|
-
return PeerAction.LowToleranceError;
|
|
57
|
-
}
|
|
47
|
+
// A dial failure means we could not open a stream. That is evidence about the transport, not
|
|
48
|
+
// about the peer's behavior, and it is dominated by transient congestion on our side, so
|
|
49
|
+
// penalize leniently for every method to avoid self-inflicted peer starvation (#9562). A
|
|
50
|
+
// genuinely dead peer still accumulates penalty and is eventually evicted, freeing the slot.
|
|
51
|
+
return PeerAction.HighToleranceError;
|
|
58
52
|
// TODO: Detect SSZDecodeError and return PeerAction.Fatal
|
|
59
53
|
|
|
60
54
|
case RequestErrorCode.RESP_TIMEOUT:
|
package/src/network/util.ts
CHANGED
|
@@ -23,11 +23,6 @@ export function getConnection(libp2p: Libp2p, peerIdStr: string): Connection | u
|
|
|
23
23
|
return getConnectionsMap(libp2p).get(peerIdStr)?.value[0] ?? undefined;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
// https://github.com/libp2p/js-libp2p/blob/f87cba928991736d9646b3e054c367f55cab315c/packages/gossipsub/src/gossipsub.ts#L2076
|
|
27
|
-
export function isPublishToZeroPeersError(e: Error): boolean {
|
|
28
|
-
return e.message.includes("PublishError.NoPeersSubscribedToTopic");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
26
|
// https://github.com/libp2p/js-libp2p/blob/f87cba928991736d9646b3e054c367f55cab315c/packages/gossipsub/src/gossipsub.ts#L2076
|
|
32
27
|
export function isPublishDuplicateError(e: Error): boolean {
|
|
33
28
|
return e.message.includes("PublishError.Duplicate");
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {routes} from "@lodestar/api";
|
|
2
|
+
import {Logger} from "@lodestar/utils";
|
|
3
|
+
import {IBeaconChain} from "../chain/index.js";
|
|
4
|
+
import {INetwork} from "../network/index.js";
|
|
5
|
+
import {ClockEvent} from "../util/clock.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* On every epoch, drain the deferred voluntary exit pool and publish the exits that have become
|
|
9
|
+
* processable. Lives at the node layer rather than inside `BeaconChain` because publishing needs
|
|
10
|
+
* `network`, which the chain does not (and should not) depend on.
|
|
11
|
+
*/
|
|
12
|
+
export function startDeferredVoluntaryExitPublisher({
|
|
13
|
+
chain,
|
|
14
|
+
network,
|
|
15
|
+
logger,
|
|
16
|
+
signal,
|
|
17
|
+
}: {
|
|
18
|
+
chain: IBeaconChain;
|
|
19
|
+
network: INetwork;
|
|
20
|
+
logger: Logger;
|
|
21
|
+
signal: AbortSignal;
|
|
22
|
+
}): void {
|
|
23
|
+
const onEpoch = async (): Promise<void> => {
|
|
24
|
+
try {
|
|
25
|
+
// Use the cached head state directly rather than getHeadStateAtCurrentEpoch, which would regen
|
|
26
|
+
// the head forward to the current epoch. At init from a stale db-finalized state that regen can
|
|
27
|
+
// be many epoch transitions. The head state is fine here: this is a best-effort drain that
|
|
28
|
+
// re-runs every epoch, so a just-processable exit is republished next tick.
|
|
29
|
+
const state = chain.getHeadState();
|
|
30
|
+
const exits = chain.deferredVoluntaryExitPool.drainProcessableExits(state);
|
|
31
|
+
for (const exit of exits) {
|
|
32
|
+
try {
|
|
33
|
+
chain.opPool.insertVoluntaryExit(exit);
|
|
34
|
+
chain.emitter.emit(routes.events.EventType.voluntaryExit, exit);
|
|
35
|
+
await network.publishVoluntaryExit(exit);
|
|
36
|
+
logger.info("Voluntary exit successfully published for validator", {
|
|
37
|
+
validatorIndex: exit.message.validatorIndex,
|
|
38
|
+
});
|
|
39
|
+
} catch (e) {
|
|
40
|
+
logger.warn(
|
|
41
|
+
"Failed to publish deferred voluntary exit",
|
|
42
|
+
{validatorIndex: exit.message.validatorIndex},
|
|
43
|
+
e as Error
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
} catch (e) {
|
|
48
|
+
logger.warn("Failed to drain deferred voluntary exit pool", {}, e as Error);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
chain.clock.addListener(ClockEvent.epoch, onEpoch);
|
|
53
|
+
signal.addEventListener("abort", () => chain.clock.removeListener(ClockEvent.epoch, onEpoch), {once: true});
|
|
54
|
+
}
|
package/src/node/nodejs.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {setMaxListeners} from "node:events";
|
|
2
2
|
import {PrivateKey} from "@libp2p/interface";
|
|
3
3
|
import {Registry} from "prom-client";
|
|
4
|
+
import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
|
|
4
5
|
import {hasher} from "@chainsafe/persistent-merkle-tree";
|
|
5
6
|
import {BeaconApiMethods} from "@lodestar/api/beacon/server";
|
|
6
7
|
import {BeaconConfig} from "@lodestar/config";
|
|
7
8
|
import type {LoggerNode} from "@lodestar/logger/node";
|
|
8
9
|
import {ZERO_HASH_HEX} from "@lodestar/params";
|
|
9
|
-
import {IBeaconStateView,
|
|
10
|
+
import {IBeaconStateView, isStatePostBellatrix, isStatePostGloas} from "@lodestar/state-transition";
|
|
10
11
|
import {phase0} from "@lodestar/types";
|
|
11
12
|
import {sleep, toRootHex} from "@lodestar/utils";
|
|
12
13
|
import {ProcessShutdownCallback} from "@lodestar/validator";
|
|
@@ -21,6 +22,7 @@ import {Network, getReqRespHandlers} from "../network/index.js";
|
|
|
21
22
|
import {BackfillSync} from "../sync/backfill/index.js";
|
|
22
23
|
import {BeaconSync, IBeaconSync} from "../sync/index.js";
|
|
23
24
|
import {Clock} from "../util/clock.js";
|
|
25
|
+
import {startDeferredVoluntaryExitPublisher} from "./deferredVoluntaryExitPublisher.js";
|
|
24
26
|
import {runNodeNotifier} from "./notifier.js";
|
|
25
27
|
import {IBeaconNodeOptions} from "./options.js";
|
|
26
28
|
|
|
@@ -258,6 +260,11 @@ export class BeaconNode {
|
|
|
258
260
|
executionBuilder: opts.executionBuilder.enabled
|
|
259
261
|
? initializeExecutionBuilder(opts.executionBuilder, config, metrics, logger)
|
|
260
262
|
: undefined,
|
|
263
|
+
builderApiClientOpts: {
|
|
264
|
+
timeout: opts.executionBuilder.timeout,
|
|
265
|
+
// Sent with all builder api requests, unless the node runs in private mode
|
|
266
|
+
userAgent: opts.executionBuilder.userAgent,
|
|
267
|
+
},
|
|
261
268
|
});
|
|
262
269
|
|
|
263
270
|
// Load persisted data from disk to in-memory caches
|
|
@@ -334,6 +341,8 @@ export class BeaconNode {
|
|
|
334
341
|
|
|
335
342
|
void runNodeNotifier({network, chain, sync, config, logger, signal});
|
|
336
343
|
|
|
344
|
+
startDeferredVoluntaryExitPublisher({chain, network, logger, signal});
|
|
345
|
+
|
|
337
346
|
return new BeaconNode({
|
|
338
347
|
opts,
|
|
339
348
|
config,
|
package/src/sync/range/batch.ts
CHANGED
|
@@ -39,6 +39,7 @@ export enum BatchStatus {
|
|
|
39
39
|
AwaitingValidation = "AwaitingValidation",
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/** Identity of one download attempt*/
|
|
42
43
|
export type Attempt = {
|
|
43
44
|
/** The peer that made the attempt */
|
|
44
45
|
peers: PeerIdStr[];
|
|
@@ -46,6 +47,16 @@ export type Attempt = {
|
|
|
46
47
|
hash: RootHex;
|
|
47
48
|
};
|
|
48
49
|
|
|
50
|
+
/**
|
|
51
|
+
* A failed attempt that has been classified for blame.
|
|
52
|
+
*/
|
|
53
|
+
export type FailedAttempt = Attempt & {
|
|
54
|
+
/**
|
|
55
|
+
* True when the failure is evidence the peers served bad data, so they may be downscored..
|
|
56
|
+
*/
|
|
57
|
+
peerAttributable: boolean;
|
|
58
|
+
};
|
|
59
|
+
|
|
49
60
|
type TrackedRequest = {
|
|
50
61
|
/** only happen for the 1st batch in checkpoint sync */
|
|
51
62
|
parentPayload: boolean;
|
|
@@ -108,10 +119,12 @@ export type BatchMetadata = {
|
|
|
108
119
|
// Retry counters
|
|
109
120
|
downloadAttempts: number;
|
|
110
121
|
processingAttempts: number;
|
|
122
|
+
executionErrorAttempts: number;
|
|
111
123
|
|
|
112
124
|
// Cumulative peer attribution for failed attempts (only present when non-empty)
|
|
113
125
|
failedDownloadPeers?: string;
|
|
114
126
|
failedProcessingPeers?: string;
|
|
127
|
+
executionErrorPeers?: string;
|
|
115
128
|
};
|
|
116
129
|
|
|
117
130
|
function formatRangeReq(req: {startSlot: Slot; count: number}): string {
|
|
@@ -152,10 +165,10 @@ export class Batch {
|
|
|
152
165
|
state: BatchState = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
153
166
|
/** Peers that provided good data, with column coverage for by_range requests */
|
|
154
167
|
private readonly successfulDownloads = new Map<PeerIdStr, TrackedRequest>();
|
|
155
|
-
/** The
|
|
156
|
-
readonly failedProcessingAttempts:
|
|
157
|
-
/** The
|
|
158
|
-
readonly executionErrorAttempts:
|
|
168
|
+
/** The attempts that have been made and failed to send us this batch. */
|
|
169
|
+
readonly failedProcessingAttempts: FailedAttempt[] = [];
|
|
170
|
+
/** The attempts that have been made and failed because of execution malfunction. */
|
|
171
|
+
readonly executionErrorAttempts: FailedAttempt[] = [];
|
|
159
172
|
/** The number of download retries this batch has undergone due to a failed request. */
|
|
160
173
|
private readonly failedDownloadAttempts: PeerIdStr[] = [];
|
|
161
174
|
private readonly config: ChainForkConfig;
|
|
@@ -419,10 +432,18 @@ export class Batch {
|
|
|
419
432
|
}
|
|
420
433
|
|
|
421
434
|
/**
|
|
422
|
-
* Gives a list of peers from which this batch has had a failed download or
|
|
435
|
+
* Gives a list of peers from which this batch has had a failed download attempt, or a
|
|
436
|
+
* peer-attributable failed processing/execution attempt.
|
|
423
437
|
*/
|
|
424
438
|
getFailedPeers(): PeerIdStr[] {
|
|
425
|
-
return [...this.failedDownloadAttempts, ...this.
|
|
439
|
+
return [...this.failedDownloadAttempts, ...this.getPeerAttributableAttempts().flatMap((a) => a.peers)];
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Attempts whose failure is peer-attributable, across both the processing and execution error
|
|
444
|
+
*/
|
|
445
|
+
getPeerAttributableAttempts(): FailedAttempt[] {
|
|
446
|
+
return [...this.failedProcessingAttempts, ...this.executionErrorAttempts].filter((a) => a.peerAttributable);
|
|
426
447
|
}
|
|
427
448
|
|
|
428
449
|
/**
|
|
@@ -457,6 +478,7 @@ export class Batch {
|
|
|
457
478
|
getMetadata(): BatchMetadata {
|
|
458
479
|
const {blocksRequest, blobsRequest, columnsRequest, envelopesRequest} = this.requests;
|
|
459
480
|
const failedProcessingPeerList = this.failedProcessingAttempts.flatMap((a) => a.peers);
|
|
481
|
+
const executionErrorPeerList = this.executionErrorAttempts.flatMap((a) => a.peers);
|
|
460
482
|
return {
|
|
461
483
|
startEpoch: this.startEpoch,
|
|
462
484
|
startSlot: this.startSlot,
|
|
@@ -468,12 +490,16 @@ export class Batch {
|
|
|
468
490
|
...(envelopesRequest && {envelopesReq: formatRangeReq(envelopesRequest)}),
|
|
469
491
|
downloadAttempts: this.failedDownloadAttempts.length,
|
|
470
492
|
processingAttempts: this.failedProcessingAttempts.length,
|
|
493
|
+
executionErrorAttempts: this.executionErrorAttempts.length,
|
|
471
494
|
...(this.failedDownloadAttempts.length > 0 && {
|
|
472
495
|
failedDownloadPeers: this.failedDownloadAttempts.join(","),
|
|
473
496
|
}),
|
|
474
497
|
...(failedProcessingPeerList.length > 0 && {
|
|
475
498
|
failedProcessingPeers: failedProcessingPeerList.join(","),
|
|
476
499
|
}),
|
|
500
|
+
...(executionErrorPeerList.length > 0 && {
|
|
501
|
+
executionErrorPeers: executionErrorPeerList.join(","),
|
|
502
|
+
}),
|
|
477
503
|
};
|
|
478
504
|
}
|
|
479
505
|
|
|
@@ -703,11 +729,7 @@ export class Batch {
|
|
|
703
729
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.Processing));
|
|
704
730
|
}
|
|
705
731
|
|
|
706
|
-
|
|
707
|
-
this.onExecutionEngineError(this.state.attempt);
|
|
708
|
-
} else {
|
|
709
|
-
this.onProcessingError(this.state.attempt);
|
|
710
|
-
}
|
|
732
|
+
this.routeProcessingFailure(err, this.state.attempt);
|
|
711
733
|
}
|
|
712
734
|
|
|
713
735
|
/**
|
|
@@ -718,10 +740,17 @@ export class Batch {
|
|
|
718
740
|
throw new BatchError(this.wrongStatusErrorType(BatchStatus.AwaitingValidation));
|
|
719
741
|
}
|
|
720
742
|
|
|
721
|
-
|
|
722
|
-
|
|
743
|
+
this.routeProcessingFailure(err, this.state.attempt);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
private routeProcessingFailure(err: Error, attempt: Attempt): void {
|
|
747
|
+
const code = err instanceof BlockError || err instanceof PayloadError ? err.type.code : null;
|
|
748
|
+
const failedAttempt: FailedAttempt = {...attempt, peerAttributable: isPeerAttributableFailure(code)};
|
|
749
|
+
|
|
750
|
+
if (isExecutionEngineFailure(code)) {
|
|
751
|
+
this.onExecutionEngineError(failedAttempt);
|
|
723
752
|
} else {
|
|
724
|
-
this.onProcessingError(
|
|
753
|
+
this.onProcessingError(failedAttempt);
|
|
725
754
|
}
|
|
726
755
|
}
|
|
727
756
|
|
|
@@ -735,7 +764,7 @@ export class Batch {
|
|
|
735
764
|
return this.state.attempt;
|
|
736
765
|
}
|
|
737
766
|
|
|
738
|
-
private onExecutionEngineError(attempt:
|
|
767
|
+
private onExecutionEngineError(attempt: FailedAttempt): void {
|
|
739
768
|
this.executionErrorAttempts.push(attempt);
|
|
740
769
|
if (this.executionErrorAttempts.length > MAX_BATCH_PROCESSING_ATTEMPTS) {
|
|
741
770
|
throw new BatchError(this.errorType({code: BatchErrorCode.MAX_EXECUTION_ENGINE_ERROR_ATTEMPTS}));
|
|
@@ -746,7 +775,7 @@ export class Batch {
|
|
|
746
775
|
this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
747
776
|
}
|
|
748
777
|
|
|
749
|
-
private onProcessingError(attempt:
|
|
778
|
+
private onProcessingError(attempt: FailedAttempt): void {
|
|
750
779
|
this.failedProcessingAttempts.push(attempt);
|
|
751
780
|
if (this.failedProcessingAttempts.length > MAX_BATCH_PROCESSING_ATTEMPTS) {
|
|
752
781
|
throw new BatchError(this.errorType({code: BatchErrorCode.MAX_PROCESSING_ATTEMPTS}));
|
|
@@ -789,18 +818,44 @@ type BatchErrorMetadata = {
|
|
|
789
818
|
|
|
790
819
|
export class BatchError extends LodestarError<BatchErrorType & BatchErrorMetadata> {}
|
|
791
820
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
if (err.type.code === BlockErrorCode.EXECUTION_ENGINE_ERROR) {
|
|
798
|
-
return true;
|
|
799
|
-
}
|
|
800
|
-
|
|
821
|
+
/**
|
|
822
|
+
* Whether a processing failure is an execution-engine failure. Pre-gloas, all EL errors stay in
|
|
823
|
+
* BlockErrorCode, post-gloas, they stay in PayloadErrorCode.
|
|
824
|
+
*/
|
|
825
|
+
function isExecutionEngineFailure(code: BlockErrorCode | PayloadErrorCode | null): boolean {
|
|
801
826
|
return (
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
827
|
+
code === BlockErrorCode.EXECUTION_ENGINE_INVALID ||
|
|
828
|
+
code === BlockErrorCode.EXECUTION_ENGINE_ERROR ||
|
|
829
|
+
code === PayloadErrorCode.EXECUTION_ENGINE_INVALID ||
|
|
830
|
+
code === PayloadErrorCode.EXECUTION_ENGINE_ERROR
|
|
805
831
|
);
|
|
806
832
|
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Based on an error code, return if peer is attributable for FailedAttempt.
|
|
836
|
+
*/
|
|
837
|
+
function isPeerAttributableFailure(code: BlockErrorCode | PayloadErrorCode | null): boolean {
|
|
838
|
+
switch (code) {
|
|
839
|
+
// EL returned a definitive INVALID verdict on the payload
|
|
840
|
+
case BlockErrorCode.EXECUTION_ENGINE_INVALID:
|
|
841
|
+
case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
|
|
842
|
+
// a block or envelope signature is invalid
|
|
843
|
+
case BlockErrorCode.INVALID_SIGNATURE:
|
|
844
|
+
case PayloadErrorCode.INVALID_SIGNATURE:
|
|
845
|
+
// the block's state transition produced an invalid state root, or failed per_slot/per_block processing
|
|
846
|
+
case BlockErrorCode.INVALID_STATE_ROOT:
|
|
847
|
+
case BlockErrorCode.PER_BLOCK_PROCESSING_ERROR:
|
|
848
|
+
// the segment this peer served is internally inconsistent (in-segment link breaks, see PR #9684)
|
|
849
|
+
case BlockErrorCode.NON_LINEAR_SLOTS:
|
|
850
|
+
case BlockErrorCode.NON_LINEAR_PARENT_ROOTS:
|
|
851
|
+
case BlockErrorCode.NON_LINEAR_PAYLOAD_ROOTS:
|
|
852
|
+
// the envelope references a mismatched block root, or fails field verification
|
|
853
|
+
case BlockErrorCode.ENVELOPE_BLOCK_ROOT_MISMATCH:
|
|
854
|
+
case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
|
|
855
|
+
// the peer served a block we have explicitly blacklisted
|
|
856
|
+
case BlockErrorCode.BLACKLISTED_BLOCK:
|
|
857
|
+
return true;
|
|
858
|
+
default:
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
}
|