@lodestar/beacon-node 1.47.0-dev.d2f4b96574 → 1.47.0-dev.d79d81f994
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 +47 -18
- 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 +25 -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 +1 -1
- package/lib/api/impl/events/index.d.ts.map +1 -1
- package/lib/api/impl/events/index.js +12 -3
- package/lib/api/impl/events/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +12 -13
- 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 +238 -65
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/impl/validator/utils.d.ts +5 -0
- package/lib/api/impl/validator/utils.d.ts.map +1 -1
- package/lib/api/impl/validator/utils.js +18 -12
- 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/archiveStore/historicalState/metrics.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.js +21 -0
- package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +2 -7
- package/lib/chain/blocks/importBlock.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 +15 -7
- 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/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/builderCircuitBreaker.d.ts +6 -5
- package/lib/chain/builderCircuitBreaker.d.ts.map +1 -1
- package/lib/chain/builderCircuitBreaker.js +28 -15
- package/lib/chain/builderCircuitBreaker.js.map +1 -1
- package/lib/chain/chain.d.ts +10 -5
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +24 -9
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +2 -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/proposerPreferences.d.ts +6 -0
- package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/errors/proposerPreferences.js +1 -0
- package/lib/chain/errors/proposerPreferences.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/options.d.ts +1 -1
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +25 -7
- 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.d.ts +2 -0
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +7 -2
- 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/seenBlockProposers.d.ts +5 -1
- package/lib/chain/seenCache/seenBlockProposers.d.ts.map +1 -1
- package/lib/chain/seenCache/seenBlockProposers.js +10 -3
- package/lib/chain/seenCache/seenBlockProposers.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 +21 -7
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts +13 -3
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +147 -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.d.ts +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/validation/proposerPreferences.js +13 -4
- 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 +64 -0
- package/lib/execution/builder/apiClient.d.ts.map +1 -0
- package/lib/execution/builder/apiClient.js +184 -0
- package/lib/execution/builder/apiClient.js.map +1 -0
- package/lib/execution/builder/http.d.ts +10 -7
- package/lib/execution/builder/http.d.ts.map +1 -1
- package/lib/execution/builder/http.js +11 -8
- package/lib/execution/builder/http.js.map +1 -1
- package/lib/execution/builder/validateBid.d.ts +22 -0
- package/lib/execution/builder/validateBid.d.ts.map +1 -0
- package/lib/execution/builder/validateBid.js +111 -0
- package/lib/execution/builder/validateBid.js.map +1 -0
- package/lib/metrics/metrics/beacon.d.ts +3 -3
- package/lib/metrics/metrics/beacon.d.ts.map +1 -1
- package/lib/metrics/metrics/beacon.js +9 -9
- package/lib/metrics/metrics/beacon.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +88 -23
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +164 -52
- 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/libp2p/index.d.ts.map +1 -1
- package/lib/network/libp2p/index.js +10 -2
- package/lib/network/libp2p/index.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 +38 -7
- 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 +41 -17
- 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 +23 -10
- package/lib/sync/range/chain.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 +15 -2
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +234 -63
- 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 +55 -21
- package/src/api/impl/beacon/pool/index.ts +27 -2
- package/src/api/impl/beacon/state/utils.ts +2 -1
- package/src/api/impl/events/index.ts +12 -4
- package/src/api/impl/lodestar/index.ts +12 -13
- package/src/api/impl/validator/index.ts +300 -69
- package/src/api/impl/validator/utils.ts +30 -15
- package/src/api/rest/base.ts +7 -0
- package/src/chain/archiveStore/archiveStore.ts +1 -1
- package/src/chain/archiveStore/historicalState/metrics.ts +22 -0
- package/src/chain/blocks/importBlock.ts +1 -6
- package/src/chain/blocks/importExecutionPayload.ts +12 -11
- package/src/chain/blocks/index.ts +19 -7
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
- 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/builderCircuitBreaker.ts +31 -17
- package/src/chain/chain.ts +27 -7
- package/src/chain/errors/blockError.ts +9 -3
- package/src/chain/errors/proposerPreferences.ts +7 -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/options.ts +1 -1
- package/src/chain/prepareNextSlot.ts +25 -7
- package/src/chain/produceBlock/computeNewStateRoot.ts +3 -38
- package/src/chain/produceBlock/produceBlockBody.ts +14 -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/seenBlockProposers.ts +13 -3
- 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 +21 -7
- package/src/chain/validation/executionPayloadBid.ts +168 -14
- package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
- package/src/chain/validation/payloadAttestationMessage.ts +6 -17
- package/src/chain/validation/proposerPreferences.ts +15 -5
- package/src/chain/validation/proposerSlashing.ts +1 -1
- package/src/chain/validation/voluntaryExit.ts +59 -2
- package/src/execution/builder/apiClient.ts +244 -0
- package/src/execution/builder/http.ts +11 -11
- package/src/execution/builder/validateBid.ts +166 -0
- package/src/metrics/metrics/beacon.ts +9 -9
- package/src/metrics/metrics/lodestar.ts +178 -58
- package/src/network/gossip/topic.ts +38 -0
- package/src/network/libp2p/index.ts +11 -2
- package/src/network/network.ts +29 -54
- package/src/network/processor/constants.ts +6 -0
- package/src/network/processor/gossipHandlers.ts +41 -5
- package/src/network/processor/gossipQueues/indexed.ts +0 -1
- package/src/network/processor/index.ts +53 -21
- 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 +26 -11
- package/src/sync/types.ts +36 -1
- package/src/sync/unknownBlock.ts +273 -70
- 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
|
@@ -414,3 +414,41 @@ export const gossipTopicIgnoreDuplicatePublishError: Record<GossipType, boolean>
|
|
|
414
414
|
[GossipType.execution_payload_bid]: true,
|
|
415
415
|
[GossipType.proposer_preferences]: true,
|
|
416
416
|
};
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Whether a publish that reached zero subscribed peers is an acceptable outcome for a topic.
|
|
420
|
+
*
|
|
421
|
+
* Publishing to a topic with no subscribed peers throws `PublishError.NoPeersSubscribedToTopic`, which
|
|
422
|
+
* propagates to the caller and, for messages submitted through the beacon API, is surfaced to the
|
|
423
|
+
* validator client. That is the right default: a message that reached nobody is a failed broadcast, and a
|
|
424
|
+
* VC configured with several beacon nodes can fall back to another one.
|
|
425
|
+
*
|
|
426
|
+
* Only topics that have a concrete reason to tolerate it opt out here, ie. are set to `true`, and the
|
|
427
|
+
* reason is named on the entry. Everything else is `false` and keeps raising. Note this is applied per
|
|
428
|
+
* publish, a topic set to `false` still honors the global `--network.allowPublishToZeroPeers` flag.
|
|
429
|
+
*/
|
|
430
|
+
export const gossipTopicAllowPublishToZeroPeers: Record<GossipType, boolean> = {
|
|
431
|
+
[GossipType.beacon_block]: false,
|
|
432
|
+
[GossipType.blob_sidecar]: false,
|
|
433
|
+
// data_column_sidecar: we ensure having all topic peers via prioritizePeers(). Even with 0 peers on the
|
|
434
|
+
// topic the overall publish can still succeed, because a supernode rebuilds and publishes the missing
|
|
435
|
+
// columns for us, so track sent peers as 0 instead of raising
|
|
436
|
+
[GossipType.data_column_sidecar]: true,
|
|
437
|
+
[GossipType.beacon_aggregate_and_proof]: false,
|
|
438
|
+
[GossipType.beacon_attestation]: false,
|
|
439
|
+
[GossipType.voluntary_exit]: false,
|
|
440
|
+
[GossipType.proposer_slashing]: false,
|
|
441
|
+
[GossipType.attester_slashing]: false,
|
|
442
|
+
[GossipType.sync_committee_contribution_and_proof]: false,
|
|
443
|
+
[GossipType.sync_committee]: false,
|
|
444
|
+
// light_client_finality_update and light_client_optimistic_update: non-mandatory route on most of the
|
|
445
|
+
// network as of Oct 2022, there may be no peer subscribed to the topic at all. Reason carried over from
|
|
446
|
+
// the handlers in network.ts, which used to swallow the error instead
|
|
447
|
+
[GossipType.light_client_finality_update]: true,
|
|
448
|
+
[GossipType.light_client_optimistic_update]: true,
|
|
449
|
+
[GossipType.bls_to_execution_change]: false,
|
|
450
|
+
[GossipType.execution_payload]: false,
|
|
451
|
+
[GossipType.payload_attestation_message]: false,
|
|
452
|
+
[GossipType.execution_payload_bid]: false,
|
|
453
|
+
[GossipType.proposer_preferences]: false,
|
|
454
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {getCiphers} from "node:crypto";
|
|
1
2
|
import {bootstrap} from "@libp2p/bootstrap";
|
|
2
3
|
import {identify} from "@libp2p/identify";
|
|
3
4
|
import type {PrivateKey} from "@libp2p/interface";
|
|
@@ -9,12 +10,20 @@ import {Libp2pInit, createLibp2p} from "libp2p";
|
|
|
9
10
|
import {Registry} from "prom-client";
|
|
10
11
|
import {ENR} from "@chainsafe/enr";
|
|
11
12
|
import {noise} from "@chainsafe/libp2p-noise";
|
|
12
|
-
import {defaultCrypto} from "@chainsafe/libp2p-noise/crypto";
|
|
13
|
+
import {asCrypto, defaultCrypto} from "@chainsafe/libp2p-noise/crypto";
|
|
13
14
|
import {quic} from "@chainsafe/libp2p-quic";
|
|
14
15
|
import {Libp2p, LodestarComponents} from "../interface.js";
|
|
15
16
|
import {NetworkOptions, defaultNetworkOptions} from "../options.js";
|
|
16
17
|
import {Eth2PeerDataStore} from "../peers/datastore.js";
|
|
17
18
|
|
|
19
|
+
const noiseCrypto = getCiphers().includes("chacha20-poly1305")
|
|
20
|
+
? defaultCrypto
|
|
21
|
+
: {
|
|
22
|
+
...defaultCrypto,
|
|
23
|
+
chaCha20Poly1305Encrypt: asCrypto.chaCha20Poly1305Encrypt,
|
|
24
|
+
chaCha20Poly1305Decrypt: asCrypto.chaCha20Poly1305Decrypt,
|
|
25
|
+
};
|
|
26
|
+
|
|
18
27
|
export type NodeJsLibp2pOpts = {
|
|
19
28
|
peerStoreDir?: string;
|
|
20
29
|
disablePeerDiscovery?: boolean;
|
|
@@ -122,7 +131,7 @@ export async function createNodeJsLibp2p(
|
|
|
122
131
|
listen: localMultiaddrs,
|
|
123
132
|
announce: [],
|
|
124
133
|
},
|
|
125
|
-
connectionEncrypters: [noise({crypto:
|
|
134
|
+
connectionEncrypters: [noise({crypto: noiseCrypto})],
|
|
126
135
|
transports,
|
|
127
136
|
streamMuxers: [mplex({disconnectThreshold})],
|
|
128
137
|
peerDiscovery,
|
package/src/network/network.ts
CHANGED
|
@@ -49,7 +49,12 @@ import {INetworkCore, NetworkCore, WorkerNetworkCore} from "./core/index.js";
|
|
|
49
49
|
import {INetworkEventBus, NetworkEvent, NetworkEventBus, NetworkEventData} from "./events.js";
|
|
50
50
|
import {getActiveForkBoundaries} from "./forks.js";
|
|
51
51
|
import {GossipHandlers, GossipTopicMap, GossipType, GossipTypeMap} from "./gossip/index.js";
|
|
52
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
getGossipSSZType,
|
|
54
|
+
gossipTopicAllowPublishToZeroPeers,
|
|
55
|
+
gossipTopicIgnoreDuplicatePublishError,
|
|
56
|
+
stringifyGossipTopic,
|
|
57
|
+
} from "./gossip/topic.js";
|
|
53
58
|
import {INetwork} from "./interface.js";
|
|
54
59
|
import {NetworkOptions} from "./options.js";
|
|
55
60
|
import {PeerAction, PeerScoreStats} from "./peers/index.js";
|
|
@@ -65,7 +70,7 @@ import {
|
|
|
65
70
|
} from "./reqresp/utils/collect.js";
|
|
66
71
|
import {collectSequentialBlocksInRange} from "./reqresp/utils/collectSequentialBlocksInRange.js";
|
|
67
72
|
import {CommitteeSubscription} from "./subnets/index.js";
|
|
68
|
-
import {isPublishDuplicateError,
|
|
73
|
+
import {isPublishDuplicateError, prettyPrintPeerIdStr} from "./util.js";
|
|
69
74
|
|
|
70
75
|
type NetworkModules = {
|
|
71
76
|
opts: NetworkOptions;
|
|
@@ -352,9 +357,7 @@ export class Network implements INetwork {
|
|
|
352
357
|
const epoch = computeEpochAtSlot(signedBlock.message.slot);
|
|
353
358
|
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
354
359
|
|
|
355
|
-
return this.publishGossip<GossipType.beacon_block>({type: GossipType.beacon_block, boundary}, signedBlock
|
|
356
|
-
ignoreDuplicatePublishError: true,
|
|
357
|
-
});
|
|
360
|
+
return this.publishGossip<GossipType.beacon_block>({type: GossipType.beacon_block, boundary}, signedBlock);
|
|
358
361
|
}
|
|
359
362
|
|
|
360
363
|
async publishBlobSidecar(blobSidecar: deneb.BlobSidecar): Promise<number> {
|
|
@@ -363,9 +366,7 @@ export class Network implements INetwork {
|
|
|
363
366
|
|
|
364
367
|
const subnet = blobSidecar.index;
|
|
365
368
|
|
|
366
|
-
return this.publishGossip<GossipType.blob_sidecar>({type: GossipType.blob_sidecar, boundary, subnet}, blobSidecar
|
|
367
|
-
ignoreDuplicatePublishError: true,
|
|
368
|
-
});
|
|
369
|
+
return this.publishGossip<GossipType.blob_sidecar>({type: GossipType.blob_sidecar, boundary, subnet}, blobSidecar);
|
|
369
370
|
}
|
|
370
371
|
|
|
371
372
|
async publishDataColumnSidecar(
|
|
@@ -381,14 +382,7 @@ export class Network implements INetwork {
|
|
|
381
382
|
try {
|
|
382
383
|
const sentPeers = await this.publishGossip<GossipType.data_column_sidecar>(
|
|
383
384
|
{type: GossipType.data_column_sidecar, boundary, subnet},
|
|
384
|
-
dataColumnSidecar
|
|
385
|
-
{
|
|
386
|
-
// we ensure having all topic peers via prioritizePeers() function
|
|
387
|
-
// in the worse case, if there is 0 peer on the topic, the overall publish operation could be still a success
|
|
388
|
-
// because supernode will rebuild and publish missing data column sidecars for us
|
|
389
|
-
// hence we want to track sent peers as 0 instead of an error
|
|
390
|
-
allowPublishToZeroTopicPeers: true,
|
|
391
|
-
}
|
|
385
|
+
dataColumnSidecar
|
|
392
386
|
);
|
|
393
387
|
return {sentPeers, alreadyPublished: false};
|
|
394
388
|
} catch (e) {
|
|
@@ -405,8 +399,7 @@ export class Network implements INetwork {
|
|
|
405
399
|
|
|
406
400
|
return this.publishGossip<GossipType.beacon_aggregate_and_proof>(
|
|
407
401
|
{type: GossipType.beacon_aggregate_and_proof, boundary},
|
|
408
|
-
aggregateAndProof
|
|
409
|
-
{ignoreDuplicatePublishError: true}
|
|
402
|
+
aggregateAndProof
|
|
410
403
|
);
|
|
411
404
|
}
|
|
412
405
|
|
|
@@ -416,8 +409,7 @@ export class Network implements INetwork {
|
|
|
416
409
|
|
|
417
410
|
return this.publishGossip<GossipType.beacon_attestation>(
|
|
418
411
|
{type: GossipType.beacon_attestation, boundary, subnet},
|
|
419
|
-
attestation
|
|
420
|
-
{ignoreDuplicatePublishError: true}
|
|
412
|
+
attestation
|
|
421
413
|
);
|
|
422
414
|
}
|
|
423
415
|
|
|
@@ -425,9 +417,7 @@ export class Network implements INetwork {
|
|
|
425
417
|
const epoch = voluntaryExit.message.epoch;
|
|
426
418
|
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
427
419
|
|
|
428
|
-
return this.publishGossip<GossipType.voluntary_exit>({type: GossipType.voluntary_exit, boundary}, voluntaryExit
|
|
429
|
-
ignoreDuplicatePublishError: true,
|
|
430
|
-
});
|
|
420
|
+
return this.publishGossip<GossipType.voluntary_exit>({type: GossipType.voluntary_exit, boundary}, voluntaryExit);
|
|
431
421
|
}
|
|
432
422
|
|
|
433
423
|
async publishBlsToExecutionChange(blsToExecutionChange: capella.SignedBLSToExecutionChange): Promise<number> {
|
|
@@ -438,8 +428,7 @@ export class Network implements INetwork {
|
|
|
438
428
|
if (fork >= ForkSeq.capella) {
|
|
439
429
|
const publishPromise = this.publishGossip<GossipType.bls_to_execution_change>(
|
|
440
430
|
{type: GossipType.bls_to_execution_change, boundary},
|
|
441
|
-
blsToExecutionChange
|
|
442
|
-
{ignoreDuplicatePublishError: true}
|
|
431
|
+
blsToExecutionChange
|
|
443
432
|
);
|
|
444
433
|
publishChanges.push(publishPromise);
|
|
445
434
|
}
|
|
@@ -457,8 +446,7 @@ export class Network implements INetwork {
|
|
|
457
446
|
|
|
458
447
|
return this.publishGossip<GossipType.proposer_slashing>(
|
|
459
448
|
{type: GossipType.proposer_slashing, boundary},
|
|
460
|
-
proposerSlashing
|
|
461
|
-
{ignoreDuplicatePublishError: true}
|
|
449
|
+
proposerSlashing
|
|
462
450
|
);
|
|
463
451
|
}
|
|
464
452
|
|
|
@@ -478,10 +466,7 @@ export class Network implements INetwork {
|
|
|
478
466
|
|
|
479
467
|
return this.publishGossip<GossipType.sync_committee>(
|
|
480
468
|
{type: GossipType.sync_committee, boundary, subnet},
|
|
481
|
-
signature
|
|
482
|
-
{
|
|
483
|
-
ignoreDuplicatePublishError: true,
|
|
484
|
-
}
|
|
469
|
+
signature
|
|
485
470
|
);
|
|
486
471
|
}
|
|
487
472
|
|
|
@@ -491,8 +476,7 @@ export class Network implements INetwork {
|
|
|
491
476
|
|
|
492
477
|
return this.publishGossip<GossipType.sync_committee_contribution_and_proof>(
|
|
493
478
|
{type: GossipType.sync_committee_contribution_and_proof, boundary},
|
|
494
|
-
contributionAndProof
|
|
495
|
-
{ignoreDuplicatePublishError: true}
|
|
479
|
+
contributionAndProof
|
|
496
480
|
);
|
|
497
481
|
}
|
|
498
482
|
|
|
@@ -522,8 +506,7 @@ export class Network implements INetwork {
|
|
|
522
506
|
|
|
523
507
|
return this.publishGossip<GossipType.execution_payload>(
|
|
524
508
|
{type: GossipType.execution_payload, boundary},
|
|
525
|
-
signedEnvelope
|
|
526
|
-
{ignoreDuplicatePublishError: true}
|
|
509
|
+
signedEnvelope
|
|
527
510
|
);
|
|
528
511
|
}
|
|
529
512
|
|
|
@@ -534,7 +517,7 @@ export class Network implements INetwork {
|
|
|
534
517
|
return this.publishGossip<GossipType.execution_payload_bid>(
|
|
535
518
|
{type: GossipType.execution_payload_bid, boundary},
|
|
536
519
|
signedBid,
|
|
537
|
-
{
|
|
520
|
+
{floodPublish: true}
|
|
538
521
|
);
|
|
539
522
|
}
|
|
540
523
|
|
|
@@ -544,8 +527,7 @@ export class Network implements INetwork {
|
|
|
544
527
|
|
|
545
528
|
return this.publishGossip<GossipType.payload_attestation_message>(
|
|
546
529
|
{type: GossipType.payload_attestation_message, boundary},
|
|
547
|
-
payloadAttestationMessage
|
|
548
|
-
{ignoreDuplicatePublishError: true}
|
|
530
|
+
payloadAttestationMessage
|
|
549
531
|
);
|
|
550
532
|
}
|
|
551
533
|
|
|
@@ -555,24 +537,25 @@ export class Network implements INetwork {
|
|
|
555
537
|
|
|
556
538
|
return this.publishGossip<GossipType.proposer_preferences>(
|
|
557
539
|
{type: GossipType.proposer_preferences, boundary},
|
|
558
|
-
signedProposerPreferences
|
|
559
|
-
{ignoreDuplicatePublishError: true}
|
|
540
|
+
signedProposerPreferences
|
|
560
541
|
);
|
|
561
542
|
}
|
|
562
543
|
|
|
563
544
|
private async publishGossip<K extends GossipType>(
|
|
564
545
|
topic: GossipTopicMap[K],
|
|
565
546
|
object: GossipTypeMap[K],
|
|
566
|
-
opts?: PublishOpts
|
|
547
|
+
opts?: PublishOpts
|
|
567
548
|
): Promise<number> {
|
|
568
549
|
const topicStr = stringifyGossipTopic(this.config, topic);
|
|
569
550
|
const sszType = getGossipSSZType(topic);
|
|
570
551
|
const messageData = (sszType.serialize as (object: GossipTypeMap[GossipType]) => Uint8Array)(object);
|
|
571
|
-
|
|
572
|
-
...opts,
|
|
552
|
+
const publishOpts: PublishOpts = {
|
|
573
553
|
ignoreDuplicatePublishError: gossipTopicIgnoreDuplicatePublishError[topic.type],
|
|
554
|
+
// Leave undefined unless the topic opts out, so `--network.allowPublishToZeroPeers` still applies
|
|
555
|
+
allowPublishToZeroTopicPeers: gossipTopicAllowPublishToZeroPeers[topic.type] ? true : undefined,
|
|
556
|
+
...opts,
|
|
574
557
|
};
|
|
575
|
-
const sentPeers = await this.core.publishGossip(topicStr, messageData,
|
|
558
|
+
const sentPeers = await this.core.publishGossip(topicStr, messageData, publishOpts);
|
|
576
559
|
|
|
577
560
|
this.logger.verbose("Publish to topic", {topic: topicStr, sentPeers, currentSlot: this.clock.currentSlot});
|
|
578
561
|
return sentPeers;
|
|
@@ -813,11 +796,7 @@ export class Network implements INetwork {
|
|
|
813
796
|
await this.waitForSyncMessageCutoff(finalityUpdate.signatureSlot);
|
|
814
797
|
await this.publishLightClientFinalityUpdate(finalityUpdate);
|
|
815
798
|
} catch (e) {
|
|
816
|
-
|
|
817
|
-
// Remove once https://github.com/ChainSafe/js-libp2p-gossipsub/issues/367
|
|
818
|
-
if (!isPublishToZeroPeersError(e as Error)) {
|
|
819
|
-
this.logger.debug("Error on BeaconGossipHandler.onLightclientFinalityUpdate", {}, e as Error);
|
|
820
|
-
}
|
|
799
|
+
this.logger.debug("Error on BeaconGossipHandler.onLightclientFinalityUpdate", {}, e as Error);
|
|
821
800
|
}
|
|
822
801
|
};
|
|
823
802
|
|
|
@@ -830,11 +809,7 @@ export class Network implements INetwork {
|
|
|
830
809
|
await this.waitForSyncMessageCutoff(optimisticUpdate.signatureSlot);
|
|
831
810
|
await this.publishLightClientOptimisticUpdate(optimisticUpdate);
|
|
832
811
|
} catch (e) {
|
|
833
|
-
|
|
834
|
-
// Remove once https://github.com/ChainSafe/js-libp2p-gossipsub/issues/367
|
|
835
|
-
if (!isPublishToZeroPeersError(e as Error)) {
|
|
836
|
-
this.logger.debug("Error on BeaconGossipHandler.onLightclientOptimisticUpdate", {}, e as Error);
|
|
837
|
-
}
|
|
812
|
+
this.logger.debug("Error on BeaconGossipHandler.onLightclientOptimisticUpdate", {}, e as Error);
|
|
838
813
|
}
|
|
839
814
|
};
|
|
840
815
|
|
|
@@ -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) {
|
|
@@ -713,9 +715,32 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
713
715
|
const {serializedData} = gossipData;
|
|
714
716
|
|
|
715
717
|
const signedBlock = sszDeserialize(topic, serializedData);
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
718
|
+
try {
|
|
719
|
+
const blockInput = await validateBeaconBlock(signedBlock, topic.boundary.fork, peerIdStr, seenTimestampSec);
|
|
720
|
+
chain.serializedCache.set(signedBlock, serializedData);
|
|
721
|
+
handleValidBeaconBlock(blockInput, peerIdStr, seenTimestampSec);
|
|
722
|
+
} catch (e) {
|
|
723
|
+
// Spec: IGNORE the block, ie not to re-publish to peers
|
|
724
|
+
// but we should still import an equivocating (REPEAT_PROPOSAL) block into fork choice because we don't
|
|
725
|
+
// know if this block (or the 1st known block with same slot) will become canonical yet
|
|
726
|
+
if (
|
|
727
|
+
e instanceof BlockGossipError &&
|
|
728
|
+
e.type.code === BlockErrorCode.REPEAT_PROPOSAL &&
|
|
729
|
+
// this is make sure the block's proposer signature was verified, it should be true anyway
|
|
730
|
+
chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root)
|
|
731
|
+
) {
|
|
732
|
+
// blockInput was optimistically seeded in validateBeaconBlock and retained on IGNORE
|
|
733
|
+
const blockInput = chain.seenBlockInputCache.get(e.type.root);
|
|
734
|
+
if (blockInput) {
|
|
735
|
+
chain.serializedCache.set(signedBlock, serializedData);
|
|
736
|
+
// this is technically not a valid gossip block but gossip validation is a cheap subset of checks
|
|
737
|
+
// this runs the full state transition, so importing an equivocating-but-valid block here is safe.
|
|
738
|
+
handleValidBeaconBlock(blockInput, peerIdStr, seenTimestampSec);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
// rethrow so gossipValidatorFn maps IGNORE -> TopicValidatorResult.Ignore (message not forwarded)
|
|
742
|
+
throw e;
|
|
743
|
+
}
|
|
719
744
|
},
|
|
720
745
|
|
|
721
746
|
[GossipType.blob_sidecar]: async ({
|
|
@@ -1166,6 +1191,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1166
1191
|
chain.validatorMonitor?.registerExecutionPayloadEnvelope(OpSource.gossip, delaySec, signedEnvelope);
|
|
1167
1192
|
|
|
1168
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
|
|
1169
1196
|
const payloadInput = chain.seenPayloadEnvelopeInputCache.get(blockRootHex);
|
|
1170
1197
|
|
|
1171
1198
|
if (!payloadInput) {
|
|
@@ -1232,11 +1259,15 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1232
1259
|
[GossipType.payload_attestation_message]: async ({
|
|
1233
1260
|
gossipData,
|
|
1234
1261
|
topic,
|
|
1262
|
+
seenTimestampSec,
|
|
1235
1263
|
}: GossipHandlerParamGeneric<GossipType.payload_attestation_message>) => {
|
|
1236
1264
|
const {serializedData} = gossipData;
|
|
1237
1265
|
const payloadAttestationMessage = sszDeserialize(topic, serializedData);
|
|
1238
1266
|
const validationResult = await validateGossipPayloadAttestationMessage(chain, payloadAttestationMessage);
|
|
1239
1267
|
|
|
1268
|
+
const delaySec = chain.clock.secFromSlot(payloadAttestationMessage.data.slot, seenTimestampSec);
|
|
1269
|
+
metrics?.gossipPayloadAttestationMessage.elapsedTimeTillReceived.observe({source: OpSource.gossip}, delaySec);
|
|
1270
|
+
|
|
1240
1271
|
try {
|
|
1241
1272
|
const insertOutcome = chain.payloadAttestationPool.add(
|
|
1242
1273
|
payloadAttestationMessage,
|
|
@@ -1263,14 +1294,19 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1263
1294
|
[GossipType.execution_payload_bid]: async ({
|
|
1264
1295
|
gossipData,
|
|
1265
1296
|
topic,
|
|
1297
|
+
seenTimestampSec,
|
|
1266
1298
|
}: GossipHandlerParamGeneric<GossipType.execution_payload_bid>) => {
|
|
1267
1299
|
const {serializedData} = gossipData;
|
|
1268
1300
|
const executionPayloadBid = sszDeserialize(topic, serializedData);
|
|
1269
1301
|
const {proposerIndex} = await validateGossipExecutionPayloadBid(chain, executionPayloadBid);
|
|
1270
1302
|
|
|
1303
|
+
// this could be negative, because it's most likely the bid of next slot comes at this clock slot
|
|
1304
|
+
const elapsedSec = chain.clock.secFromSlot(executionPayloadBid.message.slot, seenTimestampSec);
|
|
1305
|
+
metrics?.gossipExecutionPayloadBid.elapsedTimeTillReceived.observe({source: OpSource.gossip}, elapsedSec);
|
|
1306
|
+
|
|
1271
1307
|
// Handle valid payload bid by storing in a bid pool
|
|
1272
1308
|
try {
|
|
1273
|
-
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid);
|
|
1309
|
+
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid, Math.floor(elapsedSec * 1000));
|
|
1274
1310
|
metrics?.opPool.executionPayloadBidPool.gossipInsertOutcome.inc({insertOutcome});
|
|
1275
1311
|
} catch (e) {
|
|
1276
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>()};
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
GossipValidatorBatchFn,
|
|
31
31
|
GossipValidatorFn,
|
|
32
32
|
} from "../gossip/interface.js";
|
|
33
|
+
import {MAX_PEERS_PER_ROOT} from "./constants.js";
|
|
33
34
|
import {createExtractBlockSlotRootFns} from "./extractSlotRootFns.js";
|
|
34
35
|
import {GossipHandlerOpts, ValidatorFnsModules, getGossipHandlers} from "./gossipHandlers.js";
|
|
35
36
|
import {createGossipQueues} from "./gossipQueues/index.js";
|
|
@@ -191,8 +192,12 @@ export class NetworkProcessor {
|
|
|
191
192
|
// in that case PendingGossipsubMessage needs to be stored in this Map and reprocessed once the payload comes
|
|
192
193
|
private readonly awaitingMessagesByPayloadBlockRoot: MapDef<RootHex, Set<PendingGossipsubMessage>>;
|
|
193
194
|
private awaitingPayloadMessageCount = 0;
|
|
194
|
-
private unknownBlocksBySlot = new MapDef<Slot,
|
|
195
|
-
|
|
195
|
+
private unknownBlocksBySlot = new MapDef<Slot, MapDef<RootHex, Set<PeerIdStr>>>(
|
|
196
|
+
() => new MapDef<RootHex, Set<PeerIdStr>>(() => new Set())
|
|
197
|
+
);
|
|
198
|
+
private unknownEnvelopesBySlot = new MapDef<Slot, MapDef<RootHex, Set<PeerIdStr>>>(
|
|
199
|
+
() => new MapDef<RootHex, Set<PeerIdStr>>(() => new Set())
|
|
200
|
+
);
|
|
196
201
|
|
|
197
202
|
constructor(
|
|
198
203
|
modules: NetworkProcessorModules,
|
|
@@ -271,35 +276,53 @@ export class NetworkProcessor {
|
|
|
271
276
|
* Search block via `ChainEvent.unknownBlockRoot` event
|
|
272
277
|
* 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
278
|
* 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.
|
|
279
|
+
* We forward every distinct peer that gossiped this root (not just the first) so BlockInputSync can
|
|
280
|
+
* prefer them as by-root download candidates.
|
|
274
281
|
*/
|
|
275
282
|
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
|
-
) {
|
|
283
|
+
if (this.chain.seenBlock(root)) {
|
|
281
284
|
return;
|
|
282
285
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
+
const peersForRoot = this.unknownBlocksBySlot.getOrDefault(slot);
|
|
287
|
+
const alreadySearching = peersForRoot.has(root) || this.awaitingMessagesByBlockRoot.has(root);
|
|
288
|
+
const forwardedPeers = peersForRoot.getOrDefault(root);
|
|
289
|
+
|
|
290
|
+
// brand-new search always emits (peer may be undefined)
|
|
291
|
+
let shouldEmit = !alreadySearching;
|
|
292
|
+
if (peer !== undefined && !forwardedPeers.has(peer) && forwardedPeers.size < MAX_PEERS_PER_ROOT) {
|
|
293
|
+
// First time we forward THIS peer for THIS root: emit so BlockInputSync accumulates it.
|
|
294
|
+
forwardedPeers.add(peer);
|
|
295
|
+
shouldEmit = true;
|
|
296
|
+
}
|
|
297
|
+
if (shouldEmit) {
|
|
298
|
+
this.chain.emitter.emit(ChainEvent.unknownBlockRoot, {rootHex: root, peer, source});
|
|
299
|
+
}
|
|
286
300
|
}
|
|
287
301
|
|
|
288
302
|
/**
|
|
289
303
|
* Search envelope via `ChainEvent.unknownEnvelopeBlockRoot` event
|
|
290
304
|
* 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
305
|
* 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.
|
|
306
|
+
* Same peer-forwarding + dedup behavior as searchUnknownBlock.
|
|
292
307
|
*/
|
|
293
308
|
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
|
-
) {
|
|
309
|
+
if (this.chain.seenPayloadEnvelope(root)) {
|
|
299
310
|
return;
|
|
300
311
|
}
|
|
301
|
-
this.unknownEnvelopesBySlot.getOrDefault(slot)
|
|
302
|
-
|
|
312
|
+
const peersForRoot = this.unknownEnvelopesBySlot.getOrDefault(slot);
|
|
313
|
+
// capture "already searching" BEFORE getOrDefault(root) creates the entry
|
|
314
|
+
const alreadySearching = peersForRoot.has(root) || this.awaitingMessagesByPayloadBlockRoot.has(root);
|
|
315
|
+
const forwardedPeers = peersForRoot.getOrDefault(root);
|
|
316
|
+
|
|
317
|
+
let shouldEmit = !alreadySearching; // brand-new search always emits (peer may be undefined)
|
|
318
|
+
if (peer !== undefined && !forwardedPeers.has(peer) && forwardedPeers.size < MAX_PEERS_PER_ROOT) {
|
|
319
|
+
// First time we forward THIS peer for THIS root: emit so BlockInputSync accumulates it.
|
|
320
|
+
forwardedPeers.add(peer);
|
|
321
|
+
shouldEmit = true;
|
|
322
|
+
}
|
|
323
|
+
if (shouldEmit) {
|
|
324
|
+
this.chain.emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, {rootHex: root, slot, peer, source});
|
|
325
|
+
}
|
|
303
326
|
}
|
|
304
327
|
|
|
305
328
|
private onPendingGossipsubMessage = (message: PendingGossipsubMessage): void => {
|
|
@@ -537,6 +560,7 @@ export class NetworkProcessor {
|
|
|
537
560
|
|
|
538
561
|
private pushPendingGossipsubMessageToQueue(message: PendingGossipsubMessage): void {
|
|
539
562
|
const topicType = message.topic.type;
|
|
563
|
+
message.queueAddedMs = Date.now();
|
|
540
564
|
const droppedCount = this.gossipQueues[topicType].add(message);
|
|
541
565
|
if (droppedCount) {
|
|
542
566
|
// No need to report the dropped job to gossip. It will be eventually pruned from the mcache
|
|
@@ -616,7 +640,7 @@ export class NetworkProcessor {
|
|
|
616
640
|
|
|
617
641
|
for (const [slot, roots] of this.unknownBlocksBySlot) {
|
|
618
642
|
if (slot > minSlot) continue;
|
|
619
|
-
for (const rootHex of roots) {
|
|
643
|
+
for (const rootHex of roots.keys()) {
|
|
620
644
|
const gossipMessages = this.awaitingMessagesByBlockRoot.get(rootHex);
|
|
621
645
|
if (gossipMessages !== undefined) {
|
|
622
646
|
for (const message of gossipMessages) {
|
|
@@ -641,7 +665,7 @@ export class NetworkProcessor {
|
|
|
641
665
|
|
|
642
666
|
for (const [slot, roots] of this.unknownEnvelopesBySlot) {
|
|
643
667
|
if (slot > minSlot) continue;
|
|
644
|
-
for (const rootHex of roots) {
|
|
668
|
+
for (const rootHex of roots.keys()) {
|
|
645
669
|
const gossipMessages = this.awaitingMessagesByPayloadBlockRoot.get(rootHex);
|
|
646
670
|
if (gossipMessages !== undefined) {
|
|
647
671
|
for (const message of gossipMessages) {
|
|
@@ -723,12 +747,20 @@ export class NetworkProcessor {
|
|
|
723
747
|
for (const msg of messageOrArray) {
|
|
724
748
|
msg.startProcessUnixSec = nowSec;
|
|
725
749
|
if (msg.queueAddedMs !== undefined) {
|
|
726
|
-
this.metrics?.gossipValidationQueue.queueTime.observe(
|
|
750
|
+
this.metrics?.gossipValidationQueue.queueTime.observe(
|
|
751
|
+
{topic: msg.topic.type},
|
|
752
|
+
nowSec - msg.queueAddedMs / 1000
|
|
753
|
+
);
|
|
727
754
|
}
|
|
728
755
|
}
|
|
729
756
|
} else {
|
|
730
|
-
// indexed queue is not used here
|
|
731
757
|
messageOrArray.startProcessUnixSec = nowSec;
|
|
758
|
+
if (messageOrArray.queueAddedMs !== undefined) {
|
|
759
|
+
this.metrics?.gossipValidationQueue.queueTime.observe(
|
|
760
|
+
{topic: messageOrArray.topic.type},
|
|
761
|
+
nowSec - messageOrArray.queueAddedMs / 1000
|
|
762
|
+
);
|
|
763
|
+
}
|
|
732
764
|
}
|
|
733
765
|
|
|
734
766
|
const acceptanceArr = Array.isArray(messageOrArray)
|
|
@@ -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
|
+
}
|