@lodestar/beacon-node 1.50.0-dev.ebecebb9ba → 1.50.0-dev.f0a5c36612
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 +23 -3
- 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 +23 -1
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +6 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +18 -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 +4 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.js +5 -3
- package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +11 -3
- 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 +1 -1
- 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 +9 -5
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +56 -21
- 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/initState.d.ts +2 -9
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +5 -38
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/interface.d.ts +3 -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 +62 -18
- package/lib/chain/opPools/opPool.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +4 -4
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.js +14 -11
- package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
- package/lib/chain/opPools/utils.d.ts +4 -1
- package/lib/chain/opPools/utils.d.ts.map +1 -1
- package/lib/chain/opPools/utils.js +11 -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 +5 -2
- 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 +3 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +6 -2
- 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 +1 -0
- package/lib/chain/shufflingCache.d.ts.map +1 -1
- package/lib/chain/shufflingCache.js +4 -0
- 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 +2 -0
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +5 -0
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/buckets.d.ts +2 -1
- package/lib/db/buckets.d.ts.map +1 -1
- package/lib/db/buckets.js +1 -0
- package/lib/db/buckets.js.map +1 -1
- package/lib/db/interface.d.ts +2 -0
- 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/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/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 +1 -3
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +2 -17
- package/lib/execution/engine/http.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/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/types.d.ts +0 -8
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +1 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +4 -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/metadata.d.ts +1 -1
- package/lib/network/metadata.d.ts.map +1 -1
- package/lib/network/metadata.js +17 -17
- package/lib/network/metadata.js.map +1 -1
- package/lib/network/peers/datastore.d.ts +9 -9
- package/lib/network/peers/datastore.d.ts.map +1 -1
- package/lib/network/peers/datastore.js +36 -36
- package/lib/network/peers/datastore.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +66 -67
- 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.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +41 -26
- 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/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 +14 -7
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +132 -66
- 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/execution.d.ts +11 -11
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +6 -2
- package/lib/util/execution.js.map +1 -1
- package/package.json +17 -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 +31 -3
- package/src/api/impl/debug/index.ts +28 -19
- package/src/api/impl/validator/index.ts +24 -2
- package/src/chain/archiveStore/archiveStore.ts +26 -26
- 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 +9 -4
- package/src/chain/blocks/importBlock.ts +13 -3
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
- package/src/chain/blocks/verifyBlock.ts +1 -0
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +6 -3
- package/src/chain/chain.ts +76 -23
- 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/initState.ts +8 -60
- package/src/chain/interface.ts +3 -2
- package/src/chain/opPools/aggregatedAttestationPool.ts +34 -10
- package/src/chain/opPools/opPool.ts +91 -18
- package/src/chain/opPools/proposerPreferencesPool.ts +14 -10
- package/src/chain/opPools/utils.ts +31 -3
- package/src/chain/options.ts +3 -3
- package/src/chain/prepareNextSlot.ts +6 -3
- package/src/chain/produceBlock/computeNewStateRoot.ts +1 -1
- package/src/chain/produceBlock/produceBlockBody.ts +8 -1
- 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 +5 -0
- 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 +5 -0
- package/src/db/buckets.ts +1 -0
- package/src/db/interface.ts +2 -0
- package/src/db/repositories/earliestAvailableSlot.ts +19 -0
- package/src/db/repositories/proposerSlashing.ts +6 -1
- package/src/execution/engine/disabled.ts +0 -8
- package/src/execution/engine/http.ts +1 -30
- package/src/execution/engine/interface.ts +2 -6
- package/src/execution/engine/mock.ts +1 -19
- package/src/execution/engine/types.ts +0 -10
- package/src/index.ts +1 -1
- package/src/metrics/metrics/lodestar.ts +4 -0
- package/src/metrics/metrics.ts +21 -6
- package/src/network/metadata.ts +17 -17
- package/src/network/peers/datastore.ts +36 -36
- package/src/network/processor/gossipHandlers.ts +97 -80
- package/src/network/processor/gossipValidatorFn.ts +13 -3
- package/src/network/processor/index.ts +89 -10
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +42 -28
- package/src/node/nodejs.ts +35 -3
- 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 +156 -71
- package/src/sync/utils/downloadByRange.ts +123 -58
- package/src/util/execution.ts +17 -9
|
@@ -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) {
|
|
@@ -6,6 +6,7 @@ import {toRootHex} from "@lodestar/utils";
|
|
|
6
6
|
import {EnvelopeReconstructionError} from "../../../chain/errors/index.js";
|
|
7
7
|
import {IBeaconChain} from "../../../chain/index.js";
|
|
8
8
|
import {IBeaconDb} from "../../../db/index.js";
|
|
9
|
+
import {MAX_BODIES_PER_REQUEST} from "../../../util/execution.js";
|
|
9
10
|
import {ExecutionPayloadEnvelopesByRootRequest} from "../../../util/types.js";
|
|
10
11
|
import {prettyPrintPeerId} from "../../util.js";
|
|
11
12
|
|
|
@@ -19,10 +20,15 @@ export async function* onExecutionPayloadEnvelopesByRoot(
|
|
|
19
20
|
// The gloas req/resp spec uses MIN_EPOCHS_FOR_BLOCK_REQUESTS to define the minimum range peers MUST serve.
|
|
20
21
|
// Archival nodes may still serve older retained payloads to allow genesis sync.
|
|
21
22
|
|
|
22
|
-
// Resolve slots first so archived
|
|
23
|
+
// Resolve slots first so archived envelopes can be reconstructed in EL batches.
|
|
24
|
+
// Duplicate roots are served once, since each archived envelope costs an EL fetch and a rebuild.
|
|
23
25
|
const requests: {blockSlot: Slot; blockRootHex: RootHex}[] = [];
|
|
26
|
+
const seenRoots = new Set<RootHex>();
|
|
24
27
|
for (const root of requestBody) {
|
|
25
28
|
const rootHex = toRootHex(root);
|
|
29
|
+
if (seenRoots.has(rootHex)) continue;
|
|
30
|
+
seenRoots.add(rootHex);
|
|
31
|
+
|
|
26
32
|
const block = chain.forkChoice.getBlockHexDefaultStatus(rootHex);
|
|
27
33
|
// If the block is not in fork choice, it may be finalized. Attempt to find its slot in block archive
|
|
28
34
|
const slot = block ? block.slot : await db.blockArchive.getSlotByRoot(root);
|
|
@@ -41,35 +47,43 @@ export async function* onExecutionPayloadEnvelopesByRoot(
|
|
|
41
47
|
requests.push({blockSlot: slot, blockRootHex: rootHex});
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
)
|
|
50
|
+
// Yield between EL batches so the first response does not wait for the entire request.
|
|
51
|
+
let yielded = 0;
|
|
52
|
+
for (let i = 0; i < requests.length; i += MAX_BODIES_PER_REQUEST) {
|
|
53
|
+
const batch = requests.slice(i, i + MAX_BODIES_PER_REQUEST);
|
|
54
|
+
let envelopesBytes: (Uint8Array | null)[];
|
|
55
|
+
try {
|
|
56
|
+
// By-root allows omission, so an envelope that cannot be rebuilt is left out rather than failing the response.
|
|
57
|
+
envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(batch, "omit");
|
|
58
|
+
} catch (e) {
|
|
59
|
+
if (e instanceof EnvelopeReconstructionError) {
|
|
60
|
+
// By-root permits partial responses, so an EL failure can end the response here.
|
|
61
|
+
if (yielded > 0) return;
|
|
62
|
+
throw new ResponseError(
|
|
63
|
+
RespStatus.RESOURCE_UNAVAILABLE,
|
|
64
|
+
`Failed to reconstruct archived envelopes: ${e.message}`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
throw e;
|
|
54
68
|
}
|
|
55
|
-
throw e;
|
|
56
|
-
}
|
|
57
69
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
for (let j = 0; j < batch.length; j++) {
|
|
71
|
+
const {blockSlot, blockRootHex} = batch[j];
|
|
72
|
+
const envelopeBytes = envelopesBytes[j];
|
|
73
|
+
if (envelopeBytes) {
|
|
74
|
+
yielded++;
|
|
75
|
+
yield {
|
|
76
|
+
data: envelopeBytes,
|
|
77
|
+
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(blockSlot)),
|
|
78
|
+
};
|
|
79
|
+
} else {
|
|
80
|
+
chain.logger.debug("Cannot serve ExecutionPayloadEnvelopesByRoot: envelope not found", {
|
|
81
|
+
slot: blockSlot,
|
|
82
|
+
root: blockRootHex,
|
|
83
|
+
peer: prettyPrintPeerId(peerId),
|
|
84
|
+
client: peerClient,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
73
87
|
}
|
|
74
88
|
}
|
|
75
89
|
}
|
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/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:
|