@lodestar/beacon-node 1.50.0-dev.fef46df5ba → 1.50.0-rc.0
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 +6 -1
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/index.js +13 -0
- package/lib/api/impl/beacon/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +4 -4
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/index.js +28 -6
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +26 -18
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts +1 -0
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +49 -1
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +5 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +14 -24
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts +2 -2
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js +5 -7
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/types.d.ts +2 -2
- package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
- package/lib/chain/archiveStore/interface.d.ts +1 -1
- package/lib/chain/archiveStore/interface.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.js +2 -1
- package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
- package/lib/chain/beaconProposerCache.d.ts +6 -0
- package/lib/chain/beaconProposerCache.d.ts.map +1 -1
- package/lib/chain/beaconProposerCache.js +16 -0
- package/lib/chain/beaconProposerCache.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +18 -8
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +2 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +7 -7
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts +2 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +5 -4
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.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 +105 -36
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +7 -1
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +5 -0
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/envelopeReconstructionError.d.ts +5 -0
- package/lib/chain/errors/envelopeReconstructionError.d.ts.map +1 -1
- package/lib/chain/errors/envelopeReconstructionError.js +2 -0
- package/lib/chain/errors/envelopeReconstructionError.js.map +1 -1
- package/lib/chain/errors/gossipValidation.d.ts +3 -1
- package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
- package/lib/chain/errors/gossipValidation.js +2 -0
- package/lib/chain/errors/gossipValidation.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +2 -0
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +5 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.d.ts +4 -2
- package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +30 -8
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/opPool.d.ts +5 -4
- package/lib/chain/opPools/opPool.d.ts.map +1 -1
- package/lib/chain/opPools/opPool.js +60 -38
- package/lib/chain/opPools/opPool.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +8 -4
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.js +27 -12
- package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
- package/lib/chain/opPools/utils.d.ts +15 -1
- package/lib/chain/opPools/utils.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +33 -1
- package/lib/chain/opPools/utils.js.map +1 -1
- package/lib/chain/options.d.ts +2 -1
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +1 -1
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +16 -5
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +46 -30
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/regen.d.ts +2 -0
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +10 -4
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.d.ts +7 -0
- package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.js +21 -0
- package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +9 -2
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +23 -13
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/shufflingCache.d.ts +18 -8
- package/lib/chain/shufflingCache.d.ts.map +1 -1
- package/lib/chain/shufflingCache.js +72 -18
- package/lib/chain/shufflingCache.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts +4 -4
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +3 -0
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.d.ts +3 -3
- package/lib/chain/validation/proposerSlashing.d.ts.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +3 -0
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +5 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +64 -54
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/db/beacon.d.ts +4 -1
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +6 -1
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/buckets.d.ts +3 -1
- package/lib/db/buckets.d.ts.map +1 -1
- package/lib/db/buckets.js +2 -0
- package/lib/db/buckets.js.map +1 -1
- package/lib/db/interface.d.ts +4 -1
- package/lib/db/interface.d.ts.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
- package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
- package/lib/db/repositories/earliestAvailableSlot.d.ts +11 -0
- package/lib/db/repositories/earliestAvailableSlot.d.ts.map +1 -0
- package/lib/db/repositories/earliestAvailableSlot.js +19 -0
- package/lib/db/repositories/earliestAvailableSlot.js.map +1 -0
- package/lib/db/repositories/index.d.ts +1 -0
- package/lib/db/repositories/index.d.ts.map +1 -1
- package/lib/db/repositories/index.js +1 -0
- package/lib/db/repositories/index.js.map +1 -1
- package/lib/db/repositories/proposerPreferences.d.ts +14 -0
- package/lib/db/repositories/proposerPreferences.d.ts.map +1 -0
- package/lib/db/repositories/proposerPreferences.js +21 -0
- package/lib/db/repositories/proposerPreferences.js.map +1 -0
- package/lib/db/repositories/proposerSlashing.d.ts +1 -0
- package/lib/db/repositories/proposerSlashing.d.ts.map +1 -1
- package/lib/db/repositories/proposerSlashing.js +5 -1
- package/lib/db/repositories/proposerSlashing.js.map +1 -1
- package/lib/execution/engine/blobVersionedHashes.d.ts +9 -0
- package/lib/execution/engine/blobVersionedHashes.d.ts.map +1 -0
- package/lib/execution/engine/blobVersionedHashes.js +74 -0
- package/lib/execution/engine/blobVersionedHashes.js.map +1 -0
- package/lib/execution/engine/disabled.d.ts +0 -2
- package/lib/execution/engine/disabled.d.ts.map +1 -1
- package/lib/execution/engine/disabled.js +0 -6
- package/lib/execution/engine/disabled.js.map +1 -1
- package/lib/execution/engine/http.d.ts +46 -16
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +236 -213
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/index.d.ts +3 -2
- package/lib/execution/engine/index.d.ts.map +1 -1
- package/lib/execution/engine/index.js +33 -8
- package/lib/execution/engine/index.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +2 -4
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/jsonRpcTransport.d.ts +25 -0
- package/lib/execution/engine/jsonRpcTransport.d.ts.map +1 -0
- package/lib/execution/engine/jsonRpcTransport.js +158 -0
- package/lib/execution/engine/jsonRpcTransport.js.map +1 -0
- package/lib/execution/engine/mock.d.ts +0 -2
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +0 -8
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/execution/engine/restHttpClient.d.ts +71 -0
- package/lib/execution/engine/restHttpClient.d.ts.map +1 -0
- package/lib/execution/engine/restHttpClient.js +201 -0
- package/lib/execution/engine/restHttpClient.js.map +1 -0
- package/lib/execution/engine/restTransport.d.ts +46 -0
- package/lib/execution/engine/restTransport.d.ts.map +1 -0
- package/lib/execution/engine/restTransport.js +399 -0
- package/lib/execution/engine/restTransport.js.map +1 -0
- package/lib/execution/engine/sszTypes.d.ts +1261 -0
- package/lib/execution/engine/sszTypes.d.ts.map +1 -0
- package/lib/execution/engine/sszTypes.js +216 -0
- package/lib/execution/engine/sszTypes.js.map +1 -0
- package/lib/execution/engine/transport.d.ts +39 -0
- package/lib/execution/engine/transport.d.ts.map +1 -0
- package/lib/execution/engine/transport.js +2 -0
- package/lib/execution/engine/transport.js.map +1 -0
- package/lib/execution/engine/types.d.ts +2 -8
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +24 -57
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/execution/engine/utils.d.ts.map +1 -1
- package/lib/execution/engine/utils.js +9 -2
- package/lib/execution/engine/utils.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +10 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +22 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/metrics/metrics.d.ts +7 -3
- package/lib/metrics/metrics.d.ts.map +1 -1
- package/lib/metrics/metrics.js +4 -4
- package/lib/metrics/metrics.js.map +1 -1
- package/lib/network/core/events.d.ts +5 -1
- package/lib/network/core/events.d.ts.map +1 -1
- package/lib/network/core/events.js +8 -0
- package/lib/network/core/events.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +67 -68
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipValidatorFn.d.ts +7 -3
- package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
- package/lib/network/processor/gossipValidatorFn.js +7 -3
- package/lib/network/processor/gossipValidatorFn.js.map +1 -1
- package/lib/network/processor/index.d.ts +9 -0
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +77 -10
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/node/nodejs.d.ts +3 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +27 -4
- package/lib/node/nodejs.js.map +1 -1
- package/lib/node/options.d.ts +3 -2
- package/lib/node/options.d.ts.map +1 -1
- package/lib/node/options.js +2 -2
- package/lib/node/options.js.map +1 -1
- package/lib/sync/range/batch.d.ts +11 -5
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +21 -17
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +4 -4
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +12 -6
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +75 -29
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +5 -2
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +49 -24
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +38 -14
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +84 -39
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/util/asyncIterableToEvents.d.ts +10 -2
- package/lib/util/asyncIterableToEvents.d.ts.map +1 -1
- package/lib/util/asyncIterableToEvents.js +29 -3
- package/lib/util/asyncIterableToEvents.js.map +1 -1
- package/lib/util/execution.d.ts +9 -11
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +5 -1
- package/lib/util/execution.js.map +1 -1
- package/lib/util/metadata.d.ts.map +1 -1
- package/lib/util/metadata.js +2 -1
- package/lib/util/metadata.js.map +1 -1
- package/package.json +18 -17
- package/src/api/impl/beacon/blocks/index.ts +7 -4
- package/src/api/impl/beacon/index.ts +15 -0
- package/src/api/impl/beacon/pool/index.ts +4 -4
- package/src/api/impl/beacon/state/index.ts +43 -6
- package/src/api/impl/debug/index.ts +28 -19
- package/src/api/impl/validator/index.ts +61 -2
- package/src/chain/archiveStore/archiveStore.ts +19 -25
- package/src/chain/archiveStore/historicalState/getHistoricalState.ts +5 -7
- package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -1
- package/src/chain/archiveStore/historicalState/types.ts +2 -2
- package/src/chain/archiveStore/historicalState/worker.ts +1 -2
- package/src/chain/archiveStore/interface.ts +1 -1
- package/src/chain/archiveStore/utils/pruneHistory.ts +4 -1
- package/src/chain/beaconProposerCache.ts +19 -1
- package/src/chain/blocks/importBlock.ts +21 -7
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
- package/src/chain/blocks/verifyBlock.ts +8 -6
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +6 -3
- package/src/chain/chain.ts +135 -38
- package/src/chain/emitter.ts +7 -1
- package/src/chain/errors/envelopeReconstructionError.ts +3 -0
- package/src/chain/errors/gossipValidation.ts +2 -0
- package/src/chain/forkChoice/index.ts +2 -0
- package/src/chain/interface.ts +5 -2
- package/src/chain/opPools/aggregatedAttestationPool.ts +34 -10
- package/src/chain/opPools/opPool.ts +89 -46
- package/src/chain/opPools/proposerPreferencesPool.ts +34 -11
- package/src/chain/opPools/utils.ts +62 -3
- package/src/chain/options.ts +3 -3
- package/src/chain/prepareNextSlot.ts +21 -6
- package/src/chain/produceBlock/computeNewStateRoot.ts +1 -1
- package/src/chain/produceBlock/produceBlockBody.ts +76 -35
- package/src/chain/regen/regen.ts +12 -4
- package/src/chain/seenCache/seenGossipBlockInput.ts +23 -0
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +31 -13
- package/src/chain/shufflingCache.ts +84 -22
- package/src/chain/validation/attesterSlashing.ts +7 -4
- package/src/chain/validation/proposerSlashing.ts +7 -4
- package/src/chain/validatorMonitor.ts +75 -57
- package/src/db/beacon.ts +6 -0
- package/src/db/buckets.ts +2 -0
- package/src/db/interface.ts +4 -0
- package/src/db/repositories/earliestAvailableSlot.ts +19 -0
- package/src/db/repositories/index.ts +1 -0
- package/src/db/repositories/proposerPreferences.ts +23 -0
- package/src/db/repositories/proposerSlashing.ts +6 -1
- package/src/execution/engine/blobVersionedHashes.ts +72 -0
- package/src/execution/engine/disabled.ts +0 -8
- package/src/execution/engine/http.ts +304 -300
- package/src/execution/engine/index.ts +41 -7
- package/src/execution/engine/interface.ts +2 -6
- package/src/execution/engine/jsonRpcTransport.ts +247 -0
- package/src/execution/engine/mock.ts +1 -19
- package/src/execution/engine/restHttpClient.ts +269 -0
- package/src/execution/engine/restTransport.ts +544 -0
- package/src/execution/engine/sszTypes.ts +354 -0
- package/src/execution/engine/transport.ts +61 -0
- package/src/execution/engine/types.ts +34 -84
- package/src/execution/engine/utils.ts +12 -2
- package/src/metrics/metrics/lodestar.ts +23 -0
- package/src/metrics/metrics.ts +21 -6
- package/src/network/core/events.ts +16 -1
- package/src/network/processor/gossipHandlers.ts +98 -81
- package/src/network/processor/gossipValidatorFn.ts +13 -3
- package/src/network/processor/index.ts +89 -10
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +1 -1
- package/src/node/nodejs.ts +35 -3
- package/src/node/options.ts +10 -1
- package/src/sync/range/batch.ts +25 -19
- package/src/sync/range/chain.ts +15 -8
- package/src/sync/range/range.ts +76 -30
- package/src/sync/unknownBlock.ts +62 -25
- package/src/sync/utils/downloadByRange.ts +123 -58
- package/src/util/asyncIterableToEvents.ts +44 -5
- package/src/util/execution.ts +16 -8
- package/src/util/metadata.ts +2 -1
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
getParentRootFromSignedBeaconBlockSerialized,
|
|
23
23
|
getPayloadPresentFromPayloadAttestationMessageSerialized,
|
|
24
24
|
} from "../../util/sszBytes.js";
|
|
25
|
+
import {INetworkCore} from "../core/index.js";
|
|
25
26
|
import {NetworkEvent, NetworkEventBus} from "../events.js";
|
|
26
27
|
import {
|
|
27
28
|
GossipHandlers,
|
|
@@ -34,7 +35,12 @@ import {MAX_PEERS_PER_ROOT} from "./constants.js";
|
|
|
34
35
|
import {createExtractBlockSlotRootFns} from "./extractSlotRootFns.js";
|
|
35
36
|
import {GossipHandlerOpts, ValidatorFnsModules, getGossipHandlers} from "./gossipHandlers.js";
|
|
36
37
|
import {createGossipQueues} from "./gossipQueues/index.js";
|
|
37
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
ValidatorFnModules,
|
|
40
|
+
getGossipValidatorBatchFn,
|
|
41
|
+
getGossipValidatorFn,
|
|
42
|
+
rejectPeerAction,
|
|
43
|
+
} from "./gossipValidatorFn.js";
|
|
38
44
|
import {PendingGossipsubMessage} from "./types.js";
|
|
39
45
|
|
|
40
46
|
export * from "./types.js";
|
|
@@ -102,6 +108,12 @@ type SearchedRootEntry = {
|
|
|
102
108
|
*/
|
|
103
109
|
const DEFAULT_EARLIEST_PERMISSIBLE_SLOT_DISTANCE = 32;
|
|
104
110
|
|
|
111
|
+
/**
|
|
112
|
+
* The network worker bans a Fatal peer only on its next PeerManager heartbeat (30s). Until then the main thread
|
|
113
|
+
* would keep validating that peer's messages, so drop them here. 3 slots (36s) outlasts one heartbeat.
|
|
114
|
+
*/
|
|
115
|
+
export const FATAL_PEER_EXPIRY_SLOTS = 3;
|
|
116
|
+
|
|
105
117
|
type WorkOpts = {
|
|
106
118
|
bypassQueue?: boolean;
|
|
107
119
|
};
|
|
@@ -232,6 +244,7 @@ type SearchUnknownRootTarget =
|
|
|
232
244
|
*/
|
|
233
245
|
export class NetworkProcessor {
|
|
234
246
|
private readonly chain: IBeaconChain;
|
|
247
|
+
private readonly core: INetworkCore;
|
|
235
248
|
private readonly events: NetworkEventBus;
|
|
236
249
|
private readonly logger: Logger;
|
|
237
250
|
private readonly metrics: Metrics | null;
|
|
@@ -256,23 +269,31 @@ export class NetworkProcessor {
|
|
|
256
269
|
() => new MapDef<RootHex, SearchedRootEntry>(() => ({}))
|
|
257
270
|
);
|
|
258
271
|
private bufferedRootsBySlot = new MapDef<Slot, Set<RootHex>>(() => new Set());
|
|
272
|
+
/** peer -> clock slot when it was Fatal'ed */
|
|
273
|
+
private readonly fatalPeers = new Map<PeerIdStr, Slot>();
|
|
259
274
|
|
|
260
275
|
constructor(
|
|
261
276
|
modules: NetworkProcessorModules,
|
|
262
277
|
private readonly opts: NetworkProcessorOpts
|
|
263
278
|
) {
|
|
264
|
-
const {chain, events, logger, metrics} = modules;
|
|
279
|
+
const {chain, core, events, logger, metrics} = modules;
|
|
265
280
|
this.chain = chain;
|
|
281
|
+
this.core = core;
|
|
266
282
|
this.events = events;
|
|
267
283
|
this.metrics = metrics;
|
|
268
284
|
this.logger = logger;
|
|
269
285
|
this.events = events;
|
|
270
286
|
this.gossipQueues = createGossipQueues();
|
|
271
287
|
this.gossipTopicConcurrency = mapValues(this.gossipQueues, () => 0);
|
|
272
|
-
this.gossipValidatorFn = getGossipValidatorFn(
|
|
288
|
+
this.gossipValidatorFn = getGossipValidatorFn(
|
|
289
|
+
modules.gossipHandlers ?? getGossipHandlers(modules, opts),
|
|
290
|
+
modules,
|
|
291
|
+
this.onFatalPeer
|
|
292
|
+
);
|
|
273
293
|
this.gossipValidatorBatchFn = getGossipValidatorBatchFn(
|
|
274
294
|
modules.gossipHandlers ?? getGossipHandlers(modules, opts),
|
|
275
|
-
modules
|
|
295
|
+
modules,
|
|
296
|
+
this.onFatalPeer
|
|
276
297
|
);
|
|
277
298
|
|
|
278
299
|
events.on(NetworkEvent.pendingGossipsubMessage, this.onPendingGossipsubMessage);
|
|
@@ -406,19 +427,47 @@ export class NetworkProcessor {
|
|
|
406
427
|
}
|
|
407
428
|
}
|
|
408
429
|
|
|
430
|
+
private onFatalPeer = (peer: PeerIdStr): void => {
|
|
431
|
+
this.fatalPeers.set(peer, this.chain.clock.currentSlot);
|
|
432
|
+
};
|
|
433
|
+
|
|
409
434
|
private onPendingGossipsubMessage = (message: PendingGossipsubMessage): void => {
|
|
410
435
|
const topicType = message.topic.type;
|
|
436
|
+
if (this.fatalPeers.has(message.propagationSource)) {
|
|
437
|
+
this.metrics?.networkProcessor.gossipValidationError.inc({topic: topicType, error: GossipErrorCode.FATAL_PEER});
|
|
438
|
+
// No need to report the dropped job to gossip. It will be eventually pruned from the mcache
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
411
442
|
const extractBlockSlotRootFn = this.extractBlockSlotRootFns[topicType];
|
|
443
|
+
if (extractBlockSlotRootFn === undefined) {
|
|
444
|
+
// some messages don't have slot and root
|
|
445
|
+
this.pushPendingGossipsubMessageToQueue(message);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
412
448
|
|
|
413
449
|
// 1st extract round: make sure slot is in range and if block root is not available
|
|
414
450
|
// proactively search for it + queue the message
|
|
415
|
-
const slotRoot = extractBlockSlotRootFn
|
|
416
|
-
? extractBlockSlotRootFn(message.msg.data, message.topic.boundary.fork)
|
|
417
|
-
: null;
|
|
451
|
+
const slotRoot = extractBlockSlotRootFn(message.msg.data, message.topic.boundary.fork);
|
|
418
452
|
if (slotRoot === null) {
|
|
419
|
-
//
|
|
420
|
-
|
|
421
|
-
|
|
453
|
+
// DOS protection: null means malformed bytes or slot >= 2^32, neither is forwarded by honest peers.
|
|
454
|
+
const {propagationSource, clientAgent, clientVersion} = message;
|
|
455
|
+
const code = GossipErrorCode.INVALID_SLOT;
|
|
456
|
+
const peerAction = rejectPeerAction(topicType, code);
|
|
457
|
+
this.metrics?.networkProcessor.gossipValidationReject.inc({topic: topicType});
|
|
458
|
+
this.core.reportPeer(propagationSource, peerAction, code);
|
|
459
|
+
this.logger.debug(`Gossip validation ${topicType} rejected due to null slot`, {
|
|
460
|
+
peer: propagationSource,
|
|
461
|
+
clientAgent,
|
|
462
|
+
clientVersion,
|
|
463
|
+
peerAction,
|
|
464
|
+
code,
|
|
465
|
+
});
|
|
466
|
+
this.events.emit(NetworkEvent.gossipMessageValidationResult, {
|
|
467
|
+
msgId: message.msgId,
|
|
468
|
+
propagationSource,
|
|
469
|
+
acceptance: TopicValidatorResult.Reject,
|
|
470
|
+
});
|
|
422
471
|
return;
|
|
423
472
|
}
|
|
424
473
|
|
|
@@ -872,6 +921,10 @@ export class NetworkProcessor {
|
|
|
872
921
|
for (const slot of this.bufferedRootsBySlot.keys()) {
|
|
873
922
|
if (slot <= minSlot) this.bufferedRootsBySlot.delete(slot);
|
|
874
923
|
}
|
|
924
|
+
|
|
925
|
+
for (const [peer, slot] of this.fatalPeers) {
|
|
926
|
+
if (clockSlot - slot > FATAL_PEER_EXPIRY_SLOTS) this.fatalPeers.delete(peer);
|
|
927
|
+
}
|
|
875
928
|
};
|
|
876
929
|
|
|
877
930
|
private executeWork(): void {
|
|
@@ -927,6 +980,32 @@ export class NetworkProcessor {
|
|
|
927
980
|
private async processPendingGossipsubMessage(
|
|
928
981
|
messageOrArray: PendingGossipsubMessage | PendingGossipsubMessage[]
|
|
929
982
|
): Promise<void> {
|
|
983
|
+
// drop messages from peers Fatal'ed after these were queued or started awaiting a block/envelope
|
|
984
|
+
// No need to report the dropped jobs to gossip. They will be eventually pruned from the mcache
|
|
985
|
+
if (this.fatalPeers.size > 0) {
|
|
986
|
+
if (Array.isArray(messageOrArray)) {
|
|
987
|
+
const allowed: PendingGossipsubMessage[] = [];
|
|
988
|
+
for (const msg of messageOrArray) {
|
|
989
|
+
if (this.fatalPeers.has(msg.propagationSource)) {
|
|
990
|
+
this.metrics?.networkProcessor.gossipValidationError.inc({
|
|
991
|
+
topic: msg.topic.type,
|
|
992
|
+
error: GossipErrorCode.FATAL_PEER,
|
|
993
|
+
});
|
|
994
|
+
} else {
|
|
995
|
+
allowed.push(msg);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
if (allowed.length === 0) return;
|
|
999
|
+
messageOrArray = allowed;
|
|
1000
|
+
} else if (this.fatalPeers.has(messageOrArray.propagationSource)) {
|
|
1001
|
+
this.metrics?.networkProcessor.gossipValidationError.inc({
|
|
1002
|
+
topic: messageOrArray.topic.type,
|
|
1003
|
+
error: GossipErrorCode.FATAL_PEER,
|
|
1004
|
+
});
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
930
1009
|
const nowSec = Date.now() / 1000;
|
|
931
1010
|
if (Array.isArray(messageOrArray)) {
|
|
932
1011
|
for (const msg of messageOrArray) {
|
|
@@ -53,7 +53,7 @@ export async function* onExecutionPayloadEnvelopesByRoot(
|
|
|
53
53
|
const batch = requests.slice(i, i + MAX_BODIES_PER_REQUEST);
|
|
54
54
|
let envelopesBytes: (Uint8Array | null)[];
|
|
55
55
|
try {
|
|
56
|
-
// By-root allows omission, so
|
|
56
|
+
// By-root allows omission, so an envelope that cannot be rebuilt is left out rather than failing the response.
|
|
57
57
|
envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(batch, "omit");
|
|
58
58
|
} catch (e) {
|
|
59
59
|
if (e instanceof EnvelopeReconstructionError) {
|
package/src/node/nodejs.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import {setMaxListeners} from "node:events";
|
|
2
2
|
import {PrivateKey} from "@libp2p/interface";
|
|
3
3
|
import {Registry} from "prom-client";
|
|
4
|
+
import {
|
|
5
|
+
init as initNativeMetrics,
|
|
6
|
+
registerLocalValidator as registerNativeLocalValidator,
|
|
7
|
+
scrapeMetrics as scrapeNativeMetrics,
|
|
8
|
+
unregisterLocalValidator as unregisterNativeLocalValidator,
|
|
9
|
+
} from "@chainsafe/lodestar-z/metrics";
|
|
4
10
|
import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
|
|
5
11
|
import {hasher} from "@chainsafe/persistent-merkle-tree";
|
|
6
12
|
import {BeaconApiMethods} from "@lodestar/api/beacon/server";
|
|
@@ -8,6 +14,7 @@ import {BeaconConfig} from "@lodestar/config";
|
|
|
8
14
|
import type {LoggerNode} from "@lodestar/logger/node";
|
|
9
15
|
import {ZERO_HASH_HEX} from "@lodestar/params";
|
|
10
16
|
import {IBeaconStateView, isStatePostBellatrix, isStatePostGloas} from "@lodestar/state-transition";
|
|
17
|
+
import {Slot} from "@lodestar/types";
|
|
11
18
|
import {sleep, toRootHex} from "@lodestar/utils";
|
|
12
19
|
import {ProcessShutdownCallback} from "@lodestar/validator";
|
|
13
20
|
import {BeaconRestApiServer, getApi} from "../api/index.js";
|
|
@@ -55,6 +62,7 @@ export type BeaconNodeInitModules = {
|
|
|
55
62
|
peerStoreDir?: string;
|
|
56
63
|
anchorState: IBeaconStateView;
|
|
57
64
|
isAnchorStateFinalized: boolean;
|
|
65
|
+
earliestAvailableSlot: Slot;
|
|
58
66
|
metricsRegistries?: Registry[];
|
|
59
67
|
};
|
|
60
68
|
|
|
@@ -153,6 +161,7 @@ export class BeaconNode {
|
|
|
153
161
|
peerStoreDir,
|
|
154
162
|
anchorState,
|
|
155
163
|
isAnchorStateFinalized,
|
|
164
|
+
earliestAvailableSlot,
|
|
156
165
|
metricsRegistries = [],
|
|
157
166
|
}: BeaconNodeInitModules): Promise<T> {
|
|
158
167
|
if (hasher.name !== "hashtree") {
|
|
@@ -171,7 +180,13 @@ export class BeaconNode {
|
|
|
171
180
|
// monitoring relies on metrics data
|
|
172
181
|
opts.monitoring.endpoint
|
|
173
182
|
) {
|
|
174
|
-
|
|
183
|
+
if (opts.chain.nativeStateTransition) {
|
|
184
|
+
initNativeMetrics();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
metrics = createMetrics(opts.metrics, anchorState.genesisTime, metricsRegistries, {
|
|
188
|
+
includeStateTransitionMetrics: !opts.chain.nativeStateTransition,
|
|
189
|
+
});
|
|
175
190
|
initBeaconMetrics(metrics, anchorState);
|
|
176
191
|
// Since the db is instantiated before this, metrics must be injected manually afterwards
|
|
177
192
|
db.setMetrics(metrics.db, metrics.flatFileStore);
|
|
@@ -185,7 +200,13 @@ export class BeaconNode {
|
|
|
185
200
|
config,
|
|
186
201
|
anchorState.genesisTime,
|
|
187
202
|
logger.child({module: LoggerModule.vmon}),
|
|
188
|
-
opts.validatorMonitor
|
|
203
|
+
opts.validatorMonitor,
|
|
204
|
+
opts.chain.nativeStateTransition
|
|
205
|
+
? {
|
|
206
|
+
registerLocalValidator: registerNativeLocalValidator,
|
|
207
|
+
unregisterLocalValidator: unregisterNativeLocalValidator,
|
|
208
|
+
}
|
|
209
|
+
: null
|
|
189
210
|
)
|
|
190
211
|
: null;
|
|
191
212
|
|
|
@@ -248,6 +269,7 @@ export class BeaconNode {
|
|
|
248
269
|
validatorMonitor,
|
|
249
270
|
anchorState,
|
|
250
271
|
isAnchorStateFinalized,
|
|
272
|
+
earliestAvailableSlot,
|
|
251
273
|
executionEngine: initializeExecutionEngine(executionEngineOpts, {
|
|
252
274
|
metrics,
|
|
253
275
|
signal,
|
|
@@ -303,7 +325,17 @@ export class BeaconNode {
|
|
|
303
325
|
const metricsServer = opts.metrics.enabled
|
|
304
326
|
? await getHttpMetricsServer(opts.metrics, {
|
|
305
327
|
register: (metrics as Metrics).register,
|
|
306
|
-
getOtherMetrics: async () =>
|
|
328
|
+
getOtherMetrics: async () => {
|
|
329
|
+
const otherMetrics = await Promise.all([network.scrapeMetrics(), chain.archiveStore.scrapeMetrics()]);
|
|
330
|
+
if (opts.chain.nativeStateTransition) {
|
|
331
|
+
try {
|
|
332
|
+
otherMetrics.push(scrapeNativeMetrics());
|
|
333
|
+
} catch (e) {
|
|
334
|
+
logger.warn("Failed to scrape native state-transition metrics", {}, e as Error);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return otherMetrics;
|
|
338
|
+
},
|
|
307
339
|
logger: logger.child({module: LoggerModule.metrics}),
|
|
308
340
|
})
|
|
309
341
|
: null;
|
package/src/node/options.ts
CHANGED
|
@@ -3,12 +3,14 @@ import {ArchiveMode, DEFAULT_ARCHIVE_MODE, IChainOptions, defaultChainOptions} f
|
|
|
3
3
|
import {ValidatorMonitorOpts, defaultValidatorMonitorOpts} from "../chain/validatorMonitor.js";
|
|
4
4
|
import {DatabaseOptions, defaultDbOptions} from "../db/options.js";
|
|
5
5
|
import {
|
|
6
|
+
EngineApiMode,
|
|
6
7
|
ExecutionBuilderOpts,
|
|
7
8
|
ExecutionEngineOpts,
|
|
8
9
|
defaultExecutionBuilderHttpOpts,
|
|
9
10
|
defaultExecutionBuilderOpts,
|
|
10
11
|
defaultExecutionEngineHttpOpts,
|
|
11
12
|
defaultExecutionEngineOpts,
|
|
13
|
+
engineApiModes,
|
|
12
14
|
} from "../execution/index.js";
|
|
13
15
|
import {MetricsOptions, defaultMetricsOptions} from "../metrics/options.js";
|
|
14
16
|
import {MonitoringOptions, defaultMonitoringOptions} from "../monitoring/options.js";
|
|
@@ -19,7 +21,14 @@ import {SyncOptions, defaultSyncOptions} from "../sync/options.js";
|
|
|
19
21
|
export {allNamespaces} from "../api/rest/index.js";
|
|
20
22
|
|
|
21
23
|
// Re-export to use as default values in CLI args
|
|
22
|
-
export {
|
|
24
|
+
export {
|
|
25
|
+
defaultExecutionEngineHttpOpts,
|
|
26
|
+
defaultExecutionBuilderHttpOpts,
|
|
27
|
+
engineApiModes,
|
|
28
|
+
ArchiveMode,
|
|
29
|
+
DEFAULT_ARCHIVE_MODE,
|
|
30
|
+
};
|
|
31
|
+
export type {EngineApiMode};
|
|
23
32
|
|
|
24
33
|
export interface IBeaconNodeOptions {
|
|
25
34
|
api: ApiOptions;
|
package/src/sync/range/batch.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {IClock} from "../../util/clock.js";
|
|
|
14
14
|
import {CustodyConfig} from "../../util/dataColumns.js";
|
|
15
15
|
import {PeerIdStr} from "../../util/peerId.js";
|
|
16
16
|
import {MAX_BATCH_DOWNLOAD_ATTEMPTS, MAX_BATCH_PROCESSING_ATTEMPTS} from "../constants.js";
|
|
17
|
-
import {DownloadByRangeRequests,
|
|
17
|
+
import {DownloadByRangeRequests, ParentPayload} from "../utils/downloadByRange.js";
|
|
18
18
|
import {getBatchSlotRange, hashBlocks} from "./utils/index.js";
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -175,7 +175,7 @@ export class Batch {
|
|
|
175
175
|
private readonly clock: IClock;
|
|
176
176
|
private readonly custodyConfig: CustodyConfig;
|
|
177
177
|
private readonly isFirstBatchInChain: boolean;
|
|
178
|
-
private readonly
|
|
178
|
+
private readonly parentPayload: ParentPayload | undefined;
|
|
179
179
|
|
|
180
180
|
constructor(
|
|
181
181
|
startEpoch: Epoch,
|
|
@@ -183,7 +183,7 @@ export class Batch {
|
|
|
183
183
|
clock: IClock,
|
|
184
184
|
custodyConfig: CustodyConfig,
|
|
185
185
|
isFirstBatchInChain: boolean,
|
|
186
|
-
|
|
186
|
+
parentPayload: ParentPayload | undefined,
|
|
187
187
|
targetSlot: Slot
|
|
188
188
|
) {
|
|
189
189
|
this.config = config;
|
|
@@ -196,7 +196,7 @@ export class Batch {
|
|
|
196
196
|
this.startSlot = startSlot;
|
|
197
197
|
this.count = Math.min(count, targetSlot - startSlot + 1);
|
|
198
198
|
this.isFirstBatchInChain = isFirstBatchInChain;
|
|
199
|
-
this.
|
|
199
|
+
this.parentPayload = parentPayload;
|
|
200
200
|
this.requests = this.getRequests([]);
|
|
201
201
|
}
|
|
202
202
|
|
|
@@ -208,24 +208,19 @@ export class Batch {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
// we only know if we should download parent envelope if firstBlock is downloaded
|
|
211
|
-
if (firstBlock === undefined) return false;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
.
|
|
215
|
-
|
|
211
|
+
if (firstBlock === undefined || this.parentPayload === undefined) return false;
|
|
212
|
+
const firstBlockBid = (firstBlock.message.body as gloas.BeaconBlockBody).signedExecutionPayloadBid.message;
|
|
213
|
+
return (
|
|
214
|
+
byteArrayEquals(firstBlock.message.parentRoot, this.parentPayload.blockRoot) &&
|
|
215
|
+
byteArrayEquals(firstBlockBid.parentBlockHash, this.parentPayload.bid.blockHash)
|
|
216
|
+
);
|
|
216
217
|
}
|
|
217
218
|
|
|
218
|
-
|
|
219
|
-
if (this.
|
|
220
|
-
throw new Error(
|
|
221
|
-
`Coding error: getParentPayloadCommitments called without latestBid for parentBlockRoot=${toRootHex(parentBlockRoot)}`
|
|
222
|
-
);
|
|
219
|
+
getParentPayload(): ParentPayload {
|
|
220
|
+
if (this.parentPayload === undefined) {
|
|
221
|
+
throw new Error("Coding error: getParentPayload called without parentPayload");
|
|
223
222
|
}
|
|
224
|
-
return
|
|
225
|
-
blockRoot: parentBlockRoot,
|
|
226
|
-
blockRootHex: toRootHex(parentBlockRoot),
|
|
227
|
-
kzgCommitments: this.latestBid.blobKzgCommitments,
|
|
228
|
-
};
|
|
223
|
+
return this.parentPayload;
|
|
229
224
|
}
|
|
230
225
|
|
|
231
226
|
/**
|
|
@@ -773,6 +768,7 @@ export class Batch {
|
|
|
773
768
|
// remove any downloaded blocks and re-attempt
|
|
774
769
|
// TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
|
|
775
770
|
this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
771
|
+
this.resetRequests();
|
|
776
772
|
}
|
|
777
773
|
|
|
778
774
|
private onProcessingError(attempt: FailedAttempt): void {
|
|
@@ -784,6 +780,16 @@ export class Batch {
|
|
|
784
780
|
// remove any downloaded blocks and re-attempt
|
|
785
781
|
// TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
|
|
786
782
|
this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
|
|
783
|
+
this.resetRequests();
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* After a partial download `requests` only cover the data still missing from the downloaded blocks,
|
|
788
|
+
* e.g. a single column. Once those blocks are dropped, request the whole batch again, otherwise
|
|
789
|
+
* every peer fails the retry for lack of blocks to validate the data against.
|
|
790
|
+
*/
|
|
791
|
+
private resetRequests(): void {
|
|
792
|
+
this.requests = this.getRequests([]);
|
|
787
793
|
}
|
|
788
794
|
|
|
789
795
|
/** Helper to construct typed BatchError. Stack traces are correct as the error is thrown above */
|
package/src/sync/range/chain.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {Epoch, Root, Slot
|
|
2
|
+
import {Epoch, Root, Slot} from "@lodestar/types";
|
|
3
3
|
import {ErrorAborted, LodestarError, Logger, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
4
4
|
import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
|
|
5
5
|
import {BlockInputErrorCode} from "../../chain/blocks/blockInput/errors.js";
|
|
@@ -16,7 +16,7 @@ import {ItTrigger} from "../../util/itTrigger.js";
|
|
|
16
16
|
import {PeerIdStr} from "../../util/peerId.js";
|
|
17
17
|
import {WarnResult, wrapError} from "../../util/wrapError.js";
|
|
18
18
|
import {BATCH_BUFFER_SIZE, EPOCHS_PER_BATCH, MAX_LOOK_AHEAD_EPOCHS} from "../constants.js";
|
|
19
|
-
import {DownloadByRangeError, DownloadByRangeErrorCode} from "../utils/downloadByRange.js";
|
|
19
|
+
import {DownloadByRangeError, DownloadByRangeErrorCode, ParentPayload} from "../utils/downloadByRange.js";
|
|
20
20
|
import {getRateLimitedUntilMs} from "../utils/rateLimit.js";
|
|
21
21
|
import {RangeSyncType} from "../utils/remoteSyncType.js";
|
|
22
22
|
import {Batch, BatchError, BatchErrorCode, BatchMetadata, BatchStatus} from "./batch.js";
|
|
@@ -160,7 +160,7 @@ export class SyncChain {
|
|
|
160
160
|
private readonly clock: IClock;
|
|
161
161
|
private readonly metrics: Metrics | null;
|
|
162
162
|
private readonly custodyConfig: CustodyConfig;
|
|
163
|
-
private readonly
|
|
163
|
+
private readonly parentPayload: ParentPayload | undefined;
|
|
164
164
|
|
|
165
165
|
constructor(
|
|
166
166
|
initialBatchEpoch: Epoch,
|
|
@@ -168,7 +168,7 @@ export class SyncChain {
|
|
|
168
168
|
syncType: RangeSyncType,
|
|
169
169
|
fns: SyncChainFns,
|
|
170
170
|
modules: SyncChainModules,
|
|
171
|
-
|
|
171
|
+
parentPayload: ParentPayload | undefined
|
|
172
172
|
) {
|
|
173
173
|
const {config, clock, custodyConfig, logger, metrics} = modules;
|
|
174
174
|
this.firstBatchEpoch = initialBatchEpoch;
|
|
@@ -184,7 +184,7 @@ export class SyncChain {
|
|
|
184
184
|
this.clock = clock;
|
|
185
185
|
this.metrics = metrics;
|
|
186
186
|
this.custodyConfig = custodyConfig;
|
|
187
|
-
this.
|
|
187
|
+
this.parentPayload = parentPayload;
|
|
188
188
|
this.logger = logger;
|
|
189
189
|
this.logId = `${syncType}-${nextChainId++}`;
|
|
190
190
|
|
|
@@ -225,6 +225,9 @@ export class SyncChain {
|
|
|
225
225
|
Math.floor((localFinalizedEpoch - this.lastEpochWithProcessBlocks) / EPOCHS_PER_BATCH) * EPOCHS_PER_BATCH;
|
|
226
226
|
this.advanceChain(lastEpochWithProcessBlocksAligned);
|
|
227
227
|
|
|
228
|
+
// stopSyncing() cleared the retry timer, but peers can still be in rate limit backoff
|
|
229
|
+
this.scheduleRateLimitBackoffRetry();
|
|
230
|
+
|
|
228
231
|
// Potentially download new batches and process pending
|
|
229
232
|
this.triggerBatchDownloader();
|
|
230
233
|
this.triggerBatchProcessor();
|
|
@@ -417,8 +420,10 @@ export class SyncChain {
|
|
|
417
420
|
this.rateLimitBackoffTimeout = setTimeout(
|
|
418
421
|
() => {
|
|
419
422
|
this.rateLimitBackoffTimeout = undefined;
|
|
420
|
-
|
|
423
|
+
// Must run before the downloader, it drops expired peers without triggering a download. If it ran
|
|
424
|
+
// after, a backoff expiring in between would leave the peer idle with no retry scheduled.
|
|
421
425
|
this.scheduleRateLimitBackoffRetry();
|
|
426
|
+
this.triggerBatchDownloader();
|
|
422
427
|
},
|
|
423
428
|
Math.max(0, retryAt - now)
|
|
424
429
|
);
|
|
@@ -531,8 +536,8 @@ export class SyncChain {
|
|
|
531
536
|
this.clock,
|
|
532
537
|
this.custodyConfig,
|
|
533
538
|
this.isFirstBatch,
|
|
534
|
-
// `
|
|
535
|
-
this.isFirstBatch ? this.
|
|
539
|
+
// `parentPayload` is only meaningful for the first batch
|
|
540
|
+
this.isFirstBatch ? this.parentPayload : undefined,
|
|
536
541
|
this.target.slot
|
|
537
542
|
);
|
|
538
543
|
this.isFirstBatch = false;
|
|
@@ -581,6 +586,8 @@ export class SyncChain {
|
|
|
581
586
|
case DownloadByRangeErrorCode.OUT_OF_RANGE_BLOCKS:
|
|
582
587
|
case DownloadByRangeErrorCode.PARENT_ROOT_MISMATCH:
|
|
583
588
|
case DownloadByRangeErrorCode.INVALID_ENVELOPE_BEACON_BLOCK_ROOT:
|
|
589
|
+
case DownloadByRangeErrorCode.INVALID_ENVELOPE_BLOCK_HASH:
|
|
590
|
+
case DownloadByRangeErrorCode.INVALID_ENVELOPE_SLOT:
|
|
584
591
|
case DownloadByRangeErrorCode.INVALID_CHAIN_SEGMENT:
|
|
585
592
|
case BlobSidecarErrorCode.INCLUSION_PROOF_INVALID:
|
|
586
593
|
case BlobSidecarErrorCode.INVALID_KZG_PROOF_BATCH:
|
package/src/sync/range/range.ts
CHANGED
|
@@ -2,9 +2,10 @@ import {EventEmitter} from "node:events";
|
|
|
2
2
|
import {StrictEventEmitter} from "strict-event-emitter-types";
|
|
3
3
|
import {BeaconConfig} from "@lodestar/config";
|
|
4
4
|
import {IBeaconStateViewGloas, computeStartSlotAtEpoch, isStatePostGloas} from "@lodestar/state-transition";
|
|
5
|
-
import {Epoch, Status, fulu} from "@lodestar/types";
|
|
6
|
-
import {Logger, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
5
|
+
import {Epoch, Status, fulu, ssz} from "@lodestar/types";
|
|
6
|
+
import {Logger, byteArrayEquals, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
7
7
|
import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
|
|
8
|
+
import {PayloadError, PayloadErrorCode} from "../../chain/blocks/importExecutionPayload.js";
|
|
8
9
|
import {AttestationImportOpt, ImportBlockOpts} from "../../chain/blocks/index.js";
|
|
9
10
|
import {assertLinearChainSegment} from "../../chain/blocks/utils/chainSegment.js";
|
|
10
11
|
import {BlockError} from "../../chain/errors/index.js";
|
|
@@ -15,6 +16,7 @@ import {PeerIdStr} from "../../util/peerId.js";
|
|
|
15
16
|
import {
|
|
16
17
|
DownloadByRangeError,
|
|
17
18
|
DownloadByRangeErrorCode,
|
|
19
|
+
ParentPayload,
|
|
18
20
|
cacheByRangeResponses,
|
|
19
21
|
downloadByRange,
|
|
20
22
|
} from "../utils/downloadByRange.js";
|
|
@@ -207,22 +209,50 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
207
209
|
blsVerifyOnMainThread: false,
|
|
208
210
|
};
|
|
209
211
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
try {
|
|
213
|
+
if (this.opts?.disableProcessAsChainSegment) {
|
|
214
|
+
// Should only be used for debugging or testing
|
|
215
|
+
for (const block of blocks) {
|
|
216
|
+
await this.chain.processBlock(block, flags);
|
|
217
|
+
const payloadEnvelope = payloadEnvelopes?.get(block.slot);
|
|
218
|
+
if (payloadEnvelope?.hasPayloadEnvelope()) {
|
|
219
|
+
await this.chain.processExecutionPayload(payloadEnvelope);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
const {orphaned, skipped} = await this.chain.processChainSegment(blocks, payloadEnvelopes, flags);
|
|
224
|
+
// We log orphaned payloads to work with different clients
|
|
225
|
+
// in the future, consider applying penalties in certain conditions
|
|
226
|
+
// make sure the payload source was from range sync in that case
|
|
227
|
+
for (const {slot, payloadEnvelopeInput} of orphaned) {
|
|
228
|
+
const {peerIdStr, source} = payloadEnvelopeInput.getPayloadEnvelopeSource();
|
|
229
|
+
let client = "unknown";
|
|
230
|
+
if (peerIdStr !== undefined) {
|
|
231
|
+
try {
|
|
232
|
+
client = this.getConnectedPeerSyncMeta(peerIdStr).client;
|
|
233
|
+
} catch {
|
|
234
|
+
// peer disconnected since serving the envelope, keep "unknown"
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
this.logger.debug("Orphaned payload envelope in range sync batch", {
|
|
238
|
+
slot,
|
|
239
|
+
root: payloadEnvelopeInput.blockRootHex,
|
|
240
|
+
peer: peerIdStr ?? "unknown",
|
|
241
|
+
source,
|
|
242
|
+
client,
|
|
243
|
+
skipped,
|
|
244
|
+
});
|
|
217
245
|
}
|
|
218
246
|
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
247
|
+
} catch (e) {
|
|
248
|
+
if (
|
|
249
|
+
e instanceof PayloadError &&
|
|
250
|
+
(e.type.code === PayloadErrorCode.INVALID_SIGNATURE ||
|
|
251
|
+
e.type.code === PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR ||
|
|
252
|
+
e.type.code === PayloadErrorCode.EXECUTION_ENGINE_INVALID)
|
|
253
|
+
) {
|
|
254
|
+
const {payloadInput} = e;
|
|
255
|
+
const {peerIdStr, source} = payloadInput.getPayloadEnvelopeSource();
|
|
226
256
|
let client = "unknown";
|
|
227
257
|
if (peerIdStr !== undefined) {
|
|
228
258
|
try {
|
|
@@ -231,30 +261,32 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
231
261
|
// peer disconnected since serving the envelope, keep "unknown"
|
|
232
262
|
}
|
|
233
263
|
}
|
|
234
|
-
this.logger.debug("
|
|
235
|
-
slot,
|
|
236
|
-
root:
|
|
264
|
+
this.logger.debug("Removing invalid payload envelope in range sync batch", {
|
|
265
|
+
slot: payloadInput.slot,
|
|
266
|
+
root: payloadInput.blockRootHex,
|
|
237
267
|
peer: peerIdStr ?? "unknown",
|
|
238
268
|
source,
|
|
239
269
|
client,
|
|
240
|
-
|
|
270
|
+
code: e.type.code,
|
|
241
271
|
});
|
|
272
|
+
// The batch is downloaded again, it would otherwise reuse the cached envelope and fail the same way
|
|
273
|
+
this.chain.seenPayloadEnvelopeInputCache.removeInvalid(payloadInput);
|
|
242
274
|
}
|
|
275
|
+
throw e;
|
|
243
276
|
}
|
|
244
277
|
};
|
|
245
278
|
|
|
246
279
|
private downloadByRange: SyncChainFns["downloadByRange"] = async (peer, batch) => {
|
|
247
280
|
const batchBlocks = batch.getBlocks();
|
|
248
281
|
const requests = batch.getRequestsForPeer(peer);
|
|
249
|
-
const
|
|
250
|
-
const parentPayloadCommitments = parentRoot ? batch.getParentPayloadCommitments(parentRoot) : undefined;
|
|
282
|
+
const parentPayload = requests.parentPayloadRequest ? batch.getParentPayload() : undefined;
|
|
251
283
|
const {result, warnings} = await downloadByRange({
|
|
252
284
|
config: this.config,
|
|
253
285
|
network: this.network,
|
|
254
286
|
logger: this.logger,
|
|
255
287
|
peerIdStr: peer.peerId,
|
|
256
288
|
batchBlocks,
|
|
257
|
-
|
|
289
|
+
parentPayload,
|
|
258
290
|
peerDasMetrics: this.chain.metrics?.peerDas,
|
|
259
291
|
...requests,
|
|
260
292
|
});
|
|
@@ -267,6 +299,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
267
299
|
batchBlocks,
|
|
268
300
|
downloadedPayloadEnvelopes,
|
|
269
301
|
existingPayloadEnvelopes: batch.getPayloadEnvelopes(),
|
|
302
|
+
parentPayload,
|
|
270
303
|
custodyConfig: this.chain.custodyConfig,
|
|
271
304
|
seenTimestampSec: Date.now() / 1000,
|
|
272
305
|
});
|
|
@@ -344,13 +377,26 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
344
377
|
private addPeerOrCreateChain(startEpoch: Epoch, target: ChainTarget, peer: PeerIdStr, syncType: RangeSyncType): void {
|
|
345
378
|
let syncChain = this.chains.get(syncType);
|
|
346
379
|
if (!syncChain) {
|
|
347
|
-
// The first
|
|
348
|
-
//
|
|
349
|
-
// downloaded block's `bid.parentBlockHash` against the head state's `latestExecutionPayloadBid.blockHash`.
|
|
380
|
+
// The first block of the first batch may build on the head's FULL variant before its payload is imported,
|
|
381
|
+
// the batch then downloads the head's payload as dangling parent and validates it against the bid
|
|
350
382
|
const headState = this.chain.getHeadState();
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
383
|
+
let parentPayload: ParentPayload | undefined;
|
|
384
|
+
if (isStatePostGloas(headState) && headState.latestBlockHeader.slot > 0) {
|
|
385
|
+
const header = ssz.phase0.BeaconBlockHeader.clone(headState.latestBlockHeader);
|
|
386
|
+
if (byteArrayEquals(header.stateRoot, ssz.Root.defaultValue())) {
|
|
387
|
+
header.stateRoot = headState.hashTreeRoot();
|
|
388
|
+
}
|
|
389
|
+
const headRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(header);
|
|
390
|
+
const headSlot = headState.latestBlockHeader.slot;
|
|
391
|
+
parentPayload = {
|
|
392
|
+
blockRoot: headRoot,
|
|
393
|
+
blockRootHex: toRootHex(headRoot),
|
|
394
|
+
slot: headSlot,
|
|
395
|
+
proposerIndex: headState.latestBlockHeader.proposerIndex,
|
|
396
|
+
forkName: this.config.getForkName(headSlot),
|
|
397
|
+
bid: (headState as IBeaconStateViewGloas).latestExecutionPayloadBid,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
354
400
|
|
|
355
401
|
syncChain = new SyncChain(
|
|
356
402
|
startEpoch,
|
|
@@ -371,7 +417,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
|
|
|
371
417
|
custodyConfig: this.chain.custodyConfig,
|
|
372
418
|
metrics: this.metrics,
|
|
373
419
|
},
|
|
374
|
-
|
|
420
|
+
parentPayload
|
|
375
421
|
);
|
|
376
422
|
this.chains.set(syncType, syncChain);
|
|
377
423
|
|