@lodestar/beacon-node 1.48.0-dev.baa28132d2 → 1.48.0-dev.bb3ffba9e9
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 +4 -4
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +39 -39
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +1 -0
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +1 -0
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -0
- package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.js +12 -1
- package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/types.d.ts +2 -0
- package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/types.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/worker.js +4 -1
- package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +31 -34
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +0 -13
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +3 -2
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +10 -1
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.js +9 -16
- package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
- package/lib/chain/chain.d.ts +9 -3
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +127 -73
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +1 -1
- package/lib/chain/emitter.js +1 -1
- package/lib/chain/errors/blockError.d.ts +19 -7
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -2
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.d.ts +15 -2
- package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
- package/lib/chain/errors/dataColumnSidecarError.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +10 -11
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +0 -2
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +13 -13
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +46 -64
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +35 -54
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
- package/lib/chain/validation/dataColumnSidecar.js +38 -13
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +10 -29
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +7 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +22 -5
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/db/beacon.d.ts +14 -5
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +17 -3
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/dataColumnStore.d.ts +39 -0
- package/lib/db/dataColumnStore.d.ts.map +1 -0
- package/lib/db/dataColumnStore.js +81 -0
- package/lib/db/dataColumnStore.js.map +1 -0
- package/lib/db/flatFileStore/atomicWrite.d.ts +8 -0
- package/lib/db/flatFileStore/atomicWrite.d.ts.map +1 -0
- package/lib/db/flatFileStore/atomicWrite.js +61 -0
- package/lib/db/flatFileStore/atomicWrite.js.map +1 -0
- package/lib/db/flatFileStore/dcolFormat.d.ts +90 -0
- package/lib/db/flatFileStore/dcolFormat.d.ts.map +1 -0
- package/lib/db/flatFileStore/dcolFormat.js +286 -0
- package/lib/db/flatFileStore/dcolFormat.js.map +1 -0
- package/lib/db/flatFileStore/errors.d.ts +82 -0
- package/lib/db/flatFileStore/errors.d.ts.map +1 -0
- package/lib/db/flatFileStore/errors.js +32 -0
- package/lib/db/flatFileStore/errors.js.map +1 -0
- package/lib/db/flatFileStore/flatFileStore.d.ts +41 -0
- package/lib/db/flatFileStore/flatFileStore.d.ts.map +1 -0
- package/lib/db/flatFileStore/flatFileStore.js +251 -0
- package/lib/db/flatFileStore/flatFileStore.js.map +1 -0
- package/lib/db/flatFileStore/index.d.ts +4 -0
- package/lib/db/flatFileStore/index.d.ts.map +1 -0
- package/lib/db/flatFileStore/index.js +2 -0
- package/lib/db/flatFileStore/index.js.map +1 -0
- package/lib/db/flatFileStore/interface.d.ts +25 -0
- package/lib/db/flatFileStore/interface.d.ts.map +1 -0
- package/lib/db/flatFileStore/interface.js +2 -0
- package/lib/db/flatFileStore/interface.js.map +1 -0
- package/lib/db/flatFileStore/metrics.d.ts +24 -0
- package/lib/db/flatFileStore/metrics.d.ts.map +1 -0
- package/lib/db/flatFileStore/metrics.js +25 -0
- package/lib/db/flatFileStore/metrics.js.map +1 -0
- package/lib/db/flatFileStore/path.d.ts +9 -0
- package/lib/db/flatFileStore/path.d.ts.map +1 -0
- package/lib/db/flatFileStore/path.js +21 -0
- package/lib/db/flatFileStore/path.js.map +1 -0
- package/lib/db/flatFileStore/slotIndex.d.ts +14 -0
- package/lib/db/flatFileStore/slotIndex.d.ts.map +1 -0
- package/lib/db/flatFileStore/slotIndex.js +46 -0
- package/lib/db/flatFileStore/slotIndex.js.map +1 -0
- package/lib/db/flatFileStore/snappy.d.ts +3 -0
- package/lib/db/flatFileStore/snappy.d.ts.map +1 -0
- package/lib/db/flatFileStore/snappy.js +12 -0
- package/lib/db/flatFileStore/snappy.js.map +1 -0
- package/lib/db/index.d.ts +1 -0
- package/lib/db/index.d.ts.map +1 -1
- package/lib/db/interface.d.ts +8 -1
- package/lib/db/interface.d.ts.map +1 -1
- package/lib/db/repositories/blockArchive.d.ts +8 -1
- package/lib/db/repositories/blockArchive.d.ts.map +1 -1
- package/lib/db/repositories/blockArchive.js +65 -28
- package/lib/db/repositories/blockArchive.js.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.d.ts +1 -2
- package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
- package/lib/db/repositories/blockArchiveIndex.js +3 -7
- package/lib/db/repositories/blockArchiveIndex.js.map +1 -1
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +4 -1
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +18 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +55 -1
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/monitoring/clientStats.js +1 -1
- package/lib/monitoring/clientStats.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +0 -7
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +2 -1
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +4 -20
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +6 -7
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/index.d.ts +49 -3
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +232 -98
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +112 -91
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +2 -0
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/protocols.d.ts.map +1 -1
- package/lib/network/reqresp/protocols.js +6 -22
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/network/reqresp/rateLimit.js +2 -1
- package/lib/network/reqresp/rateLimit.js.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts +2 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js +14 -9
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
- package/lib/node/nodejs.d.ts +2 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +4 -2
- package/lib/node/nodejs.js.map +1 -1
- package/lib/util/sszBytes.d.ts +6 -0
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +1 -1
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +18 -19
- package/src/api/impl/beacon/blocks/index.ts +8 -4
- package/src/api/impl/validator/index.ts +44 -43
- package/src/chain/archiveStore/archiveStore.ts +6 -1
- package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -0
- package/src/chain/archiveStore/historicalState/metrics.ts +14 -1
- package/src/chain/archiveStore/historicalState/types.ts +2 -0
- package/src/chain/archiveStore/historicalState/worker.ts +4 -1
- package/src/chain/archiveStore/utils/archiveBlocks.ts +34 -39
- package/src/chain/blocks/importBlock.ts +0 -13
- package/src/chain/blocks/index.ts +13 -2
- package/src/chain/blocks/utils/chainSegment.ts +10 -1
- package/src/chain/blocks/writeBlockInputToDb.ts +10 -17
- package/src/chain/chain.ts +149 -80
- package/src/chain/emitter.ts +1 -1
- package/src/chain/errors/blockError.ts +22 -10
- package/src/chain/errors/dataColumnSidecarError.ts +24 -8
- package/src/chain/errors/executionPayloadEnvelope.ts +14 -11
- package/src/chain/interface.ts +2 -2
- package/src/chain/prepareNextSlot.ts +16 -16
- package/src/chain/produceBlock/produceBlockBody.ts +50 -71
- package/src/chain/validation/block.ts +35 -70
- package/src/chain/validation/dataColumnSidecar.ts +47 -14
- package/src/chain/validation/executionPayloadEnvelope.ts +10 -37
- package/src/chain/validatorMonitor.ts +24 -7
- package/src/db/beacon.ts +33 -6
- package/src/db/dataColumnStore.ts +113 -0
- package/src/db/flatFileStore/atomicWrite.ts +65 -0
- package/src/db/flatFileStore/dcolFormat.ts +389 -0
- package/src/db/flatFileStore/errors.ts +53 -0
- package/src/db/flatFileStore/flatFileStore.ts +310 -0
- package/src/db/flatFileStore/index.ts +3 -0
- package/src/db/flatFileStore/interface.ts +21 -0
- package/src/db/flatFileStore/metrics.ts +48 -0
- package/src/db/flatFileStore/path.ts +32 -0
- package/src/db/flatFileStore/slotIndex.ts +56 -0
- package/src/db/flatFileStore/snappy.ts +14 -0
- package/src/db/index.ts +1 -0
- package/src/db/interface.ts +9 -1
- package/src/db/repositories/blockArchive.ts +89 -30
- package/src/db/repositories/blockArchiveIndex.ts +4 -9
- package/src/execution/engine/mock.ts +4 -1
- package/src/metrics/metrics/lodestar.ts +57 -1
- package/src/monitoring/clientStats.ts +1 -1
- package/src/network/gossip/encoding.ts +0 -7
- package/src/network/gossip/topic.ts +3 -25
- package/src/network/processor/gossipHandlers.ts +11 -11
- package/src/network/processor/index.ts +263 -148
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +139 -105
- package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +2 -0
- package/src/network/reqresp/protocols.ts +7 -24
- package/src/network/reqresp/rateLimit.ts +2 -1
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +15 -7
- package/src/node/nodejs.ts +6 -1
- package/src/util/sszBytes.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {TopicValidatorResult} from "@libp2p/gossipsub";
|
|
2
2
|
import {routes} from "@lodestar/api";
|
|
3
|
-
import {ForkSeq} from "@lodestar/params";
|
|
3
|
+
import {ForkSeq, NUMBER_OF_COLUMNS} from "@lodestar/params";
|
|
4
4
|
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
5
5
|
import {RootHex, Slot, SlotRootHex} from "@lodestar/types";
|
|
6
6
|
import {Logger, MapDef, mapValues, sleep} from "@lodestar/utils";
|
|
@@ -59,6 +59,36 @@ export type NetworkProcessorOpts = GossipHandlerOpts & {
|
|
|
59
59
|
*/
|
|
60
60
|
const MAX_UNKNOWN_ROOTS_SLOT_CACHE_SIZE = 3;
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Max distinct roots we BUFFER messages for, per slot. Kept tight to avoid the OOM
|
|
64
|
+
* risk. We don't support super forky condition where there are more than this many roots per slot via gossip.
|
|
65
|
+
*/
|
|
66
|
+
export const MAX_BUFFERED_ROOTS_PER_SLOT = 5;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Max distinct roots we emit an unknown-root search for, per slot. Higher than
|
|
70
|
+
* the buffer budget because:
|
|
71
|
+
* - in the attack scenario, the genuine root may comes after the first MAX_BUFFERED_ROOTS_PER_SLOT roots
|
|
72
|
+
* - if we cannot search, we'll penalize peers in UnknownBlockInput, not in NetworkProcessor
|
|
73
|
+
*/
|
|
74
|
+
export const MAX_SEARCHED_ROOTS_PER_SLOT = 32;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Given the same root and topic, we'll ignore messages after the below cap. Each cap is the number of
|
|
78
|
+
* legitimate messages we expect for one block, plus headroom for some malformed messages that may arrives first
|
|
79
|
+
* they will be penalized by the gossip handler
|
|
80
|
+
*/
|
|
81
|
+
export const MAX_AWAITING_MESSAGES_PER_ROOT: Partial<Record<GossipType, number>> = {
|
|
82
|
+
[GossipType.data_column_sidecar]: 2 * NUMBER_OF_COLUMNS,
|
|
83
|
+
[GossipType.execution_payload]: 2,
|
|
84
|
+
[GossipType.execution_payload_bid]: 8,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Track the forwarded peers we already emit to UnknownBlockInput sync.
|
|
89
|
+
*/
|
|
90
|
+
type SearchedRootEntry = {blockPeerIds?: Set<PeerIdStr>; envelopePeerIds?: Set<PeerIdStr>};
|
|
91
|
+
|
|
62
92
|
/**
|
|
63
93
|
* This is respective to gossipsub seenTTL (which is 550 * 0.7 = 385s), also it's respective
|
|
64
94
|
* to beacon_attestation ATTESTATION_PROPAGATION_SLOT_RANGE (32 slots).
|
|
@@ -120,6 +150,14 @@ export enum ReprocessRejectReason {
|
|
|
120
150
|
* There are too many gossip messages that have unknown block root.
|
|
121
151
|
*/
|
|
122
152
|
reached_limit = "reached_limit",
|
|
153
|
+
/**
|
|
154
|
+
* Too many distinct unknown roots are already tracked for the message's slot (MAX_UNKNOWN_ROOTS_PER_SLOT).
|
|
155
|
+
*/
|
|
156
|
+
reached_root_limit = "reached_root_limit",
|
|
157
|
+
/**
|
|
158
|
+
* Too many gossip messages are already buffered for this (root, topic) (MAX_AWAITING_MESSAGES_PER_ROOT).
|
|
159
|
+
*/
|
|
160
|
+
reached_topic_limit = "reached_topic_limit",
|
|
123
161
|
/**
|
|
124
162
|
* The awaiting gossip message is pruned per clock slot.
|
|
125
163
|
*/
|
|
@@ -185,19 +223,21 @@ export class NetworkProcessor {
|
|
|
185
223
|
private readonly gossipTopicConcurrency: {[K in GossipType]: number};
|
|
186
224
|
private readonly extractBlockSlotRootFns = createExtractBlockSlotRootFns();
|
|
187
225
|
// we may not receive the block for messages like Attestation and SignedAggregateAndProof messages, in that case PendingGossipsubMessage needs
|
|
188
|
-
// to be stored in this Map and reprocessed once the block comes
|
|
189
|
-
|
|
226
|
+
// to be stored in this Map and reprocessed once the block comes. Keyed by topic per root so we can cap
|
|
227
|
+
// the number of buffered messages per (root, topic) - see MAX_AWAITING_MESSAGES_PER_ROOT.
|
|
228
|
+
private readonly awaitingMessagesByBlockRoot: MapDef<RootHex, MapDef<GossipType, Set<PendingGossipsubMessage>>>;
|
|
190
229
|
private awaitingBlockMessageCount = 0;
|
|
191
230
|
// we may not receive the payload for messages that require the FULL payload variant to be processed,
|
|
192
231
|
// in that case PendingGossipsubMessage needs to be stored in this Map and reprocessed once the payload comes
|
|
193
|
-
private readonly awaitingMessagesByPayloadBlockRoot: MapDef<
|
|
232
|
+
private readonly awaitingMessagesByPayloadBlockRoot: MapDef<
|
|
233
|
+
RootHex,
|
|
234
|
+
MapDef<GossipType, Set<PendingGossipsubMessage>>
|
|
235
|
+
>;
|
|
194
236
|
private awaitingPayloadMessageCount = 0;
|
|
195
|
-
private
|
|
196
|
-
() => new MapDef<RootHex,
|
|
197
|
-
);
|
|
198
|
-
private unknownEnvelopesBySlot = new MapDef<Slot, MapDef<RootHex, Set<PeerIdStr>>>(
|
|
199
|
-
() => new MapDef<RootHex, Set<PeerIdStr>>(() => new Set())
|
|
237
|
+
private searchedRootsBySlot = new MapDef<Slot, MapDef<RootHex, SearchedRootEntry>>(
|
|
238
|
+
() => new MapDef<RootHex, SearchedRootEntry>(() => ({}))
|
|
200
239
|
);
|
|
240
|
+
private bufferedRootsBySlot = new MapDef<Slot, Set<RootHex>>(() => new Set());
|
|
201
241
|
|
|
202
242
|
constructor(
|
|
203
243
|
modules: NetworkProcessorModules,
|
|
@@ -222,8 +262,12 @@ export class NetworkProcessor {
|
|
|
222
262
|
this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadEnvelopeProcessed);
|
|
223
263
|
this.chain.clock.on(ClockEvent.slot, this.onClockSlot);
|
|
224
264
|
|
|
225
|
-
this.awaitingMessagesByBlockRoot = new MapDef<RootHex, Set<PendingGossipsubMessage
|
|
226
|
-
|
|
265
|
+
this.awaitingMessagesByBlockRoot = new MapDef<RootHex, MapDef<GossipType, Set<PendingGossipsubMessage>>>(
|
|
266
|
+
() => new MapDef<GossipType, Set<PendingGossipsubMessage>>(() => new Set())
|
|
267
|
+
);
|
|
268
|
+
this.awaitingMessagesByPayloadBlockRoot = new MapDef<RootHex, MapDef<GossipType, Set<PendingGossipsubMessage>>>(
|
|
269
|
+
() => new MapDef<GossipType, Set<PendingGossipsubMessage>>(() => new Set())
|
|
270
|
+
);
|
|
227
271
|
|
|
228
272
|
// TODO: Implement queues and priorization for ReqResp incoming requests
|
|
229
273
|
// Listens to NetworkEvent.reqRespIncomingRequest event
|
|
@@ -283,9 +327,12 @@ export class NetworkProcessor {
|
|
|
283
327
|
if (this.chain.seenBlock(root)) {
|
|
284
328
|
return;
|
|
285
329
|
}
|
|
286
|
-
const
|
|
287
|
-
const alreadySearching =
|
|
288
|
-
|
|
330
|
+
const entry = this.searchedRootsBySlot.getOrDefault(slot).getOrDefault(root);
|
|
331
|
+
const alreadySearching = entry.blockPeerIds !== undefined;
|
|
332
|
+
if (entry.blockPeerIds === undefined) {
|
|
333
|
+
entry.blockPeerIds = new Set();
|
|
334
|
+
}
|
|
335
|
+
const forwardedPeers = entry.blockPeerIds;
|
|
289
336
|
|
|
290
337
|
// brand-new search always emits (peer may be undefined)
|
|
291
338
|
let shouldEmit = !alreadySearching;
|
|
@@ -309,10 +356,12 @@ export class NetworkProcessor {
|
|
|
309
356
|
if (this.chain.seenPayloadEnvelope(root)) {
|
|
310
357
|
return;
|
|
311
358
|
}
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
359
|
+
const entry = this.searchedRootsBySlot.getOrDefault(slot).getOrDefault(root);
|
|
360
|
+
const alreadySearching = entry.envelopePeerIds !== undefined;
|
|
361
|
+
if (entry.envelopePeerIds === undefined) {
|
|
362
|
+
entry.envelopePeerIds = new Set();
|
|
363
|
+
}
|
|
364
|
+
const forwardedPeers = entry.envelopePeerIds;
|
|
316
365
|
|
|
317
366
|
let shouldEmit = !alreadySearching; // brand-new search always emits (peer may be undefined)
|
|
318
367
|
if (peer !== undefined && !forwardedPeers.has(peer) && forwardedPeers.size < MAX_PEERS_PER_ROOT) {
|
|
@@ -374,14 +423,15 @@ export class NetworkProcessor {
|
|
|
374
423
|
}
|
|
375
424
|
|
|
376
425
|
message.msgSlot = slot;
|
|
426
|
+
const peerId = message.propagationSource.toString();
|
|
377
427
|
|
|
378
428
|
// this determines whether this message needs to wait for a Block or Envelope
|
|
379
|
-
// a message should only wait for what it voted for, hence we don't want to put it on both queues
|
|
429
|
+
// a message should only wait for what it voted for, hence we don't want to put it on both queues.
|
|
380
430
|
let preprocessResult: PreprocessResult = {action: PreprocessAction.PushToQueue};
|
|
381
431
|
// no need to check if root is a descendant of the current finalized block, it will be checked once we validate the message if needed
|
|
382
432
|
if (root && !this.chain.forkChoice.hasBlockHexUnsafe(root)) {
|
|
383
433
|
// starting from GLOAS, unknown root from data_column_sidecar also falls into this case
|
|
384
|
-
this.
|
|
434
|
+
this.searchUnknownRoot({slot, root}, true, false, peerId);
|
|
385
435
|
// for beacon_attestation and beacon_aggregate_and_proof messages, this is only temporary.
|
|
386
436
|
// if "index = 1" we need to await for the Envelope instead
|
|
387
437
|
preprocessResult = {action: PreprocessAction.AwaitBlock, root};
|
|
@@ -391,40 +441,32 @@ export class NetworkProcessor {
|
|
|
391
441
|
// we separate the search action from the await action
|
|
392
442
|
|
|
393
443
|
// beacon_block: proactively search for parent block/envelope across all forks, but never queue.
|
|
394
|
-
// BlockInputSync handles cascading recovery if the gossip handler throws.
|
|
444
|
+
// BlockInputSync handles cascading recovery if the gossip handler throws. The parent root differs from
|
|
445
|
+
// the message root and this message never awaits, so its search flushes inline here (gated by the budget).
|
|
395
446
|
if (topicType === GossipType.beacon_block) {
|
|
396
447
|
const parentRoot = getParentRootFromSignedBeaconBlockSerialized(message.msg.data);
|
|
397
448
|
if (parentRoot) {
|
|
449
|
+
let searchParentBlock = false;
|
|
450
|
+
let searchParentEnvelope = false;
|
|
398
451
|
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
399
452
|
// GLOAS: also check parent envelope, same logic as execution_payload_bid
|
|
400
453
|
const parentBlockHash = getParentBlockHashFromGloasSignedBeaconBlockSerialized(message.msg.data);
|
|
401
454
|
if (parentBlockHash && !this.chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHash)) {
|
|
402
455
|
const protoBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
|
|
403
456
|
if (protoBlock === null) {
|
|
404
|
-
|
|
405
|
-
{slot, root: parentRoot},
|
|
406
|
-
BlockInputSource.network_processor,
|
|
407
|
-
message.propagationSource.toString()
|
|
408
|
-
);
|
|
457
|
+
searchParentBlock = true;
|
|
409
458
|
} else if (
|
|
410
459
|
protoBlock.executionPayloadBlockHash &&
|
|
411
460
|
protoBlock.executionPayloadBlockHash !== parentBlockHash
|
|
412
461
|
) {
|
|
413
462
|
// only search for the envelope by block root if we're sure there is one. Otherwise UnknownBlockSync will penalize the peer.
|
|
414
|
-
|
|
415
|
-
{slot, root: parentRoot},
|
|
416
|
-
BlockInputSource.network_processor,
|
|
417
|
-
message.propagationSource.toString()
|
|
418
|
-
);
|
|
463
|
+
searchParentEnvelope = true;
|
|
419
464
|
}
|
|
420
465
|
}
|
|
421
466
|
} else if (!this.chain.forkChoice.hasBlockHexUnsafe(parentRoot)) {
|
|
422
|
-
|
|
423
|
-
{slot, root: parentRoot},
|
|
424
|
-
BlockInputSource.network_processor,
|
|
425
|
-
message.propagationSource.toString()
|
|
426
|
-
);
|
|
467
|
+
searchParentBlock = true;
|
|
427
468
|
}
|
|
469
|
+
this.searchUnknownRoot({slot, root: parentRoot}, searchParentBlock, searchParentEnvelope, peerId);
|
|
428
470
|
}
|
|
429
471
|
preprocessResult = {action: PreprocessAction.PushToQueue};
|
|
430
472
|
}
|
|
@@ -443,11 +485,7 @@ export class NetworkProcessor {
|
|
|
443
485
|
: getDataIndexFromSignedAggregateAndProofSerialized(message.msg.data);
|
|
444
486
|
if (attIndex === 1 && !this.chain.forkChoice.hasPayloadHexUnsafe(root)) {
|
|
445
487
|
// attestation votes that the payload is available but it is not yet known
|
|
446
|
-
this.
|
|
447
|
-
{slot, root},
|
|
448
|
-
BlockInputSource.network_processor,
|
|
449
|
-
message.propagationSource.toString()
|
|
450
|
-
);
|
|
488
|
+
this.searchUnknownRoot({slot, root}, false, true, peerId);
|
|
451
489
|
preprocessResult = {action: PreprocessAction.AwaitEnvelope, root};
|
|
452
490
|
}
|
|
453
491
|
break;
|
|
@@ -457,11 +495,7 @@ export class NetworkProcessor {
|
|
|
457
495
|
const payloadPresent = getPayloadPresentFromPayloadAttestationMessageSerialized(message.msg.data);
|
|
458
496
|
if (payloadPresent && !this.chain.forkChoice.hasPayloadHexUnsafe(root)) {
|
|
459
497
|
// payload attestation votes that the payload is available but it is not yet known
|
|
460
|
-
this.
|
|
461
|
-
{slot, root},
|
|
462
|
-
BlockInputSource.network_processor,
|
|
463
|
-
message.propagationSource.toString()
|
|
464
|
-
);
|
|
498
|
+
this.searchUnknownRoot({slot, root}, false, true, peerId);
|
|
465
499
|
// do not await the envelope, payload attestation processing only requires that the block is known
|
|
466
500
|
// also do not reset preprocessResult, we may already await for the block
|
|
467
501
|
}
|
|
@@ -470,11 +504,7 @@ export class NetworkProcessor {
|
|
|
470
504
|
case GossipType.data_column_sidecar: {
|
|
471
505
|
if (root == null) break;
|
|
472
506
|
if (!this.chain.forkChoice.hasPayloadHexUnsafe(root)) {
|
|
473
|
-
this.
|
|
474
|
-
{slot, root},
|
|
475
|
-
BlockInputSource.network_processor,
|
|
476
|
-
message.propagationSource.toString()
|
|
477
|
-
);
|
|
507
|
+
this.searchUnknownRoot({slot, root}, false, true, peerId);
|
|
478
508
|
// do not await the envelope, we can do gossip validation
|
|
479
509
|
// also do not reset preprocessResult, we may already await for the block
|
|
480
510
|
}
|
|
@@ -485,11 +515,7 @@ export class NetworkProcessor {
|
|
|
485
515
|
// Extract beacon_block_root directly
|
|
486
516
|
const blockRoot = getBeaconBlockRootFromExecutionPayloadEnvelopeSerialized(message.msg.data);
|
|
487
517
|
if (blockRoot && !this.chain.forkChoice.hasBlockHexUnsafe(blockRoot)) {
|
|
488
|
-
this.
|
|
489
|
-
{slot, root: blockRoot},
|
|
490
|
-
BlockInputSource.network_processor,
|
|
491
|
-
message.propagationSource.toString()
|
|
492
|
-
);
|
|
518
|
+
this.searchUnknownRoot({slot, root: blockRoot}, true, false, peerId);
|
|
493
519
|
// We always want to await the block
|
|
494
520
|
// This allows us to properly forward the payload envelope
|
|
495
521
|
preprocessResult = {action: PreprocessAction.AwaitBlock, root: blockRoot};
|
|
@@ -508,21 +534,13 @@ export class NetworkProcessor {
|
|
|
508
534
|
) {
|
|
509
535
|
const protoBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentBlockRoot);
|
|
510
536
|
if (protoBlock === null) {
|
|
511
|
-
this.
|
|
512
|
-
{slot, root: parentBlockRoot},
|
|
513
|
-
BlockInputSource.network_processor,
|
|
514
|
-
message.propagationSource.toString()
|
|
515
|
-
);
|
|
537
|
+
this.searchUnknownRoot({slot, root: parentBlockRoot}, true, false, peerId);
|
|
516
538
|
preprocessResult = {action: PreprocessAction.AwaitBlock, root: parentBlockRoot};
|
|
517
539
|
} else if (
|
|
518
540
|
protoBlock.executionPayloadBlockHash &&
|
|
519
541
|
protoBlock.executionPayloadBlockHash !== parentBlockHash
|
|
520
542
|
) {
|
|
521
|
-
this.
|
|
522
|
-
{slot, root: parentBlockRoot},
|
|
523
|
-
BlockInputSource.network_processor,
|
|
524
|
-
message.propagationSource.toString()
|
|
525
|
-
);
|
|
543
|
+
this.searchUnknownRoot({slot, root: parentBlockRoot}, false, true, peerId);
|
|
526
544
|
preprocessResult = {action: PreprocessAction.AwaitEnvelope, root: parentBlockRoot};
|
|
527
545
|
}
|
|
528
546
|
}
|
|
@@ -535,42 +553,106 @@ export class NetworkProcessor {
|
|
|
535
553
|
case PreprocessAction.PushToQueue:
|
|
536
554
|
this.pushPendingGossipsubMessageToQueue(message);
|
|
537
555
|
break;
|
|
538
|
-
case PreprocessAction.AwaitBlock:
|
|
539
|
-
|
|
540
|
-
// No need to report the dropped job to gossip. It will be eventually pruned from the mcache
|
|
541
|
-
this.metrics?.awaitingBlockGossipMessages.reject.inc({
|
|
542
|
-
reason: ReprocessRejectReason.reached_limit,
|
|
543
|
-
topic: topicType,
|
|
544
|
-
});
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
this.metrics?.awaitingBlockGossipMessages.queue.inc({topic: topicType});
|
|
549
|
-
const awaitingGossipsubMessages = this.awaitingMessagesByBlockRoot.getOrDefault(preprocessResult.root);
|
|
550
|
-
awaitingGossipsubMessages.add(message);
|
|
551
|
-
this.awaitingBlockMessageCount++;
|
|
556
|
+
case PreprocessAction.AwaitBlock:
|
|
557
|
+
this.maybeAwaitBlock(preprocessResult.root, topicType, slot, message);
|
|
552
558
|
break;
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
if (this.awaitingPayloadMessageCount > MAX_QUEUED_UNKNOWN_PAYLOAD_GOSSIP_OBJECTS) {
|
|
556
|
-
this.metrics?.awaitingPayloadGossipMessages.reject.inc({
|
|
557
|
-
reason: ReprocessRejectReason.reached_limit,
|
|
558
|
-
topic: topicType,
|
|
559
|
-
});
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
this.metrics?.awaitingPayloadGossipMessages.queue.inc({topic: topicType});
|
|
564
|
-
const awaitingPayloadGossipsubMessages = this.awaitingMessagesByPayloadBlockRoot.getOrDefault(
|
|
565
|
-
preprocessResult.root
|
|
566
|
-
);
|
|
567
|
-
awaitingPayloadGossipsubMessages.add(message);
|
|
568
|
-
this.awaitingPayloadMessageCount++;
|
|
559
|
+
case PreprocessAction.AwaitEnvelope:
|
|
560
|
+
this.maybeAwaitPayload(preprocessResult.root, topicType, slot, message);
|
|
569
561
|
break;
|
|
570
|
-
}
|
|
571
562
|
}
|
|
572
563
|
};
|
|
573
564
|
|
|
565
|
+
/**
|
|
566
|
+
* Buffer a gossip message that must wait for an unknown block before it can be validated.
|
|
567
|
+
*
|
|
568
|
+
* For DOS protection, the message is ignored (reject metric incremented) when any cap is hit:
|
|
569
|
+
* - MAX_QUEUED_UNKNOWN_BLOCK_GOSSIP_OBJECTS: global awaiting-block message count
|
|
570
|
+
* - MAX_BUFFERED_ROOTS_PER_SLOT: distinct roots we buffer messages for, per slot
|
|
571
|
+
* - MAX_AWAITING_MESSAGES_PER_ROOT[topic]: messages buffered per (root, topic)
|
|
572
|
+
*/
|
|
573
|
+
private maybeAwaitBlock(root: RootHex, topicType: GossipType, slot: Slot, message: PendingGossipsubMessage): void {
|
|
574
|
+
const metric = this.metrics?.awaitingBlockGossipMessages;
|
|
575
|
+
// global message-count cap - cheapest check first
|
|
576
|
+
if (this.awaitingBlockMessageCount > MAX_QUEUED_UNKNOWN_BLOCK_GOSSIP_OBJECTS) {
|
|
577
|
+
metric?.reject.inc({reason: ReprocessRejectReason.reached_limit, topic: topicType});
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
// per-(root, topic) message cap: e.g. <= NUMBER_OF_COLUMNS columns per root
|
|
581
|
+
const perRootCap = MAX_AWAITING_MESSAGES_PER_ROOT[topicType];
|
|
582
|
+
if (
|
|
583
|
+
perRootCap !== undefined &&
|
|
584
|
+
(this.awaitingMessagesByBlockRoot.get(root)?.get(topicType)?.size ?? 0) >= perRootCap
|
|
585
|
+
) {
|
|
586
|
+
metric?.reject.inc({reason: ReprocessRejectReason.reached_topic_limit, topic: topicType});
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
if (!this.tryReserveBufferedRoot(slot, root)) {
|
|
590
|
+
metric?.reject.inc({reason: ReprocessRejectReason.reached_root_limit, topic: topicType});
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
metric?.queue.inc({topic: topicType});
|
|
595
|
+
this.awaitingMessagesByBlockRoot.getOrDefault(root).getOrDefault(topicType).add(message);
|
|
596
|
+
this.awaitingBlockMessageCount++;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/** Payload counterpart of maybeAwaitBlock */
|
|
600
|
+
private maybeAwaitPayload(root: RootHex, topicType: GossipType, slot: Slot, message: PendingGossipsubMessage): void {
|
|
601
|
+
const metric = this.metrics?.awaitingPayloadGossipMessages;
|
|
602
|
+
if (this.awaitingPayloadMessageCount > MAX_QUEUED_UNKNOWN_PAYLOAD_GOSSIP_OBJECTS) {
|
|
603
|
+
metric?.reject.inc({reason: ReprocessRejectReason.reached_limit, topic: topicType});
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
const perRootCap = MAX_AWAITING_MESSAGES_PER_ROOT[topicType];
|
|
607
|
+
if (
|
|
608
|
+
perRootCap !== undefined &&
|
|
609
|
+
(this.awaitingMessagesByPayloadBlockRoot.get(root)?.get(topicType)?.size ?? 0) >= perRootCap
|
|
610
|
+
) {
|
|
611
|
+
metric?.reject.inc({reason: ReprocessRejectReason.reached_topic_limit, topic: topicType});
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
if (!this.tryReserveBufferedRoot(slot, root)) {
|
|
615
|
+
metric?.reject.inc({reason: ReprocessRejectReason.reached_root_limit, topic: topicType});
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
metric?.queue.inc({topic: topicType});
|
|
620
|
+
this.awaitingMessagesByPayloadBlockRoot.getOrDefault(root).getOrDefault(topicType).add(message);
|
|
621
|
+
this.awaitingPayloadMessageCount++;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Cap distinct roots we emit an unknown-root search for, an already-tracked root (dedup) never counts as "too many".
|
|
626
|
+
*/
|
|
627
|
+
private tooManySearchedRoots(slot: Slot, root: RootHex): boolean {
|
|
628
|
+
const roots = this.searchedRootsBySlot.get(slot);
|
|
629
|
+
if (roots === undefined) return false;
|
|
630
|
+
return !roots.has(root) && roots.size >= MAX_SEARCHED_ROOTS_PER_SLOT;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Cap distinct roots we buffer per slot.
|
|
635
|
+
*/
|
|
636
|
+
tryReserveBufferedRoot(slot: Slot, root: RootHex): boolean {
|
|
637
|
+
const roots = this.bufferedRootsBySlot.get(slot);
|
|
638
|
+
if (roots?.has(root)) return true;
|
|
639
|
+
if ((roots?.size ?? 0) >= MAX_BUFFERED_ROOTS_PER_SLOT) return false;
|
|
640
|
+
this.bufferedRootsBySlot.getOrDefault(slot).add(root);
|
|
641
|
+
return true;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
private searchUnknownRoot(
|
|
645
|
+
slotRoot: SlotRootHex,
|
|
646
|
+
searchBlock: boolean,
|
|
647
|
+
searchEnvelope: boolean,
|
|
648
|
+
peerId: PeerIdStr
|
|
649
|
+
): void {
|
|
650
|
+
if (!searchBlock && !searchEnvelope) return;
|
|
651
|
+
if (this.tooManySearchedRoots(slotRoot.slot, slotRoot.root)) return;
|
|
652
|
+
if (searchBlock) this.searchUnknownBlock(slotRoot, BlockInputSource.network_processor, peerId);
|
|
653
|
+
if (searchEnvelope) this.searchUnknownEnvelope(slotRoot, BlockInputSource.network_processor, peerId);
|
|
654
|
+
}
|
|
655
|
+
|
|
574
656
|
private pushPendingGossipsubMessageToQueue(message: PendingGossipsubMessage): void {
|
|
575
657
|
const topicType = message.topic.type;
|
|
576
658
|
message.queueAddedMs = Date.now();
|
|
@@ -585,64 +667,82 @@ export class NetworkProcessor {
|
|
|
585
667
|
}
|
|
586
668
|
|
|
587
669
|
private onBlockProcessed = async ({block: rootHex}: {block: string; executionOptimistic: boolean}): Promise<void> => {
|
|
588
|
-
const
|
|
589
|
-
if (
|
|
670
|
+
const messagesByTopic = this.awaitingMessagesByBlockRoot.get(rootHex);
|
|
671
|
+
if (messagesByTopic === undefined) {
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
let total = 0;
|
|
675
|
+
for (const messages of messagesByTopic.values()) {
|
|
676
|
+
total += messages.size;
|
|
677
|
+
}
|
|
678
|
+
if (total === 0) {
|
|
590
679
|
return;
|
|
591
680
|
}
|
|
592
681
|
|
|
593
682
|
// Atomically remove from map and update counter before async iteration to
|
|
594
683
|
// prevent double-decrement race with onClockSlot during yield points below
|
|
595
684
|
if (this.awaitingMessagesByBlockRoot.delete(rootHex)) {
|
|
596
|
-
this.awaitingBlockMessageCount -=
|
|
685
|
+
this.awaitingBlockMessageCount -= total;
|
|
597
686
|
}
|
|
598
687
|
|
|
599
688
|
const nowSec = Date.now() / 1000;
|
|
600
689
|
let count = 0;
|
|
601
690
|
// TODO: we can group attestations to process in batches but since we have the SeenAttestationDatas
|
|
602
691
|
// cache, it may not be necessary at this time
|
|
603
|
-
for (const
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
count
|
|
615
|
-
|
|
692
|
+
for (const messages of messagesByTopic.values()) {
|
|
693
|
+
for (const message of messages) {
|
|
694
|
+
const topicType = message.topic.type;
|
|
695
|
+
this.metrics?.awaitingBlockGossipMessages.waitSecBeforeResolve.set(
|
|
696
|
+
{topic: topicType},
|
|
697
|
+
nowSec - message.seenTimestampSec
|
|
698
|
+
);
|
|
699
|
+
this.metrics?.awaitingBlockGossipMessages.resolve.inc({topic: topicType});
|
|
700
|
+
this.pushPendingGossipsubMessageToQueue(message);
|
|
701
|
+
count++;
|
|
702
|
+
// don't want to block the event loop, worse case it'd wait for 16_084 / 1024 * 50ms = 800ms which is not a big deal
|
|
703
|
+
if (count === MAX_AWAITING_GOSSIP_OBJECTS_PER_TICK) {
|
|
704
|
+
count = 0;
|
|
705
|
+
await sleep(AWAITING_GOSSIP_OBJECTS_YIELD_EVERY_MS);
|
|
706
|
+
}
|
|
616
707
|
}
|
|
617
708
|
}
|
|
618
709
|
};
|
|
619
710
|
|
|
620
711
|
private onPayloadEnvelopeProcessed = async ({blockRoot: rootHex}: {blockRoot: RootHex}): Promise<void> => {
|
|
621
|
-
const
|
|
622
|
-
if (
|
|
712
|
+
const messagesByTopic = this.awaitingMessagesByPayloadBlockRoot.get(rootHex);
|
|
713
|
+
if (messagesByTopic === undefined) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
let total = 0;
|
|
717
|
+
for (const messages of messagesByTopic.values()) {
|
|
718
|
+
total += messages.size;
|
|
719
|
+
}
|
|
720
|
+
if (total === 0) {
|
|
623
721
|
return;
|
|
624
722
|
}
|
|
625
723
|
|
|
626
724
|
// Atomically remove from map and update counter before async iteration to
|
|
627
725
|
// prevent double-decrement race with onClockSlot during yield points below
|
|
628
726
|
if (this.awaitingMessagesByPayloadBlockRoot.delete(rootHex)) {
|
|
629
|
-
this.awaitingPayloadMessageCount -=
|
|
727
|
+
this.awaitingPayloadMessageCount -= total;
|
|
630
728
|
}
|
|
631
729
|
|
|
632
730
|
const nowSec = Date.now() / 1000;
|
|
633
731
|
let count = 0;
|
|
634
|
-
for (const
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
count
|
|
645
|
-
|
|
732
|
+
for (const messages of messagesByTopic.values()) {
|
|
733
|
+
for (const message of messages) {
|
|
734
|
+
const topicType = message.topic.type;
|
|
735
|
+
this.metrics?.awaitingPayloadGossipMessages.waitSecBeforeResolve.set(
|
|
736
|
+
{topic: topicType},
|
|
737
|
+
nowSec - message.seenTimestampSec
|
|
738
|
+
);
|
|
739
|
+
this.metrics?.awaitingPayloadGossipMessages.resolve.inc({topic: topicType});
|
|
740
|
+
this.pushPendingGossipsubMessageToQueue(message);
|
|
741
|
+
count++;
|
|
742
|
+
if (count === MAX_AWAITING_GOSSIP_OBJECTS_PER_TICK) {
|
|
743
|
+
count = 0;
|
|
744
|
+
await sleep(AWAITING_GOSSIP_OBJECTS_YIELD_EVERY_MS);
|
|
745
|
+
}
|
|
646
746
|
}
|
|
647
747
|
}
|
|
648
748
|
};
|
|
@@ -651,12 +751,19 @@ export class NetworkProcessor {
|
|
|
651
751
|
const nowSec = Date.now() / 1000;
|
|
652
752
|
const minSlot = clockSlot - MAX_UNKNOWN_ROOTS_SLOT_CACHE_SIZE;
|
|
653
753
|
|
|
654
|
-
for (const [slot,
|
|
754
|
+
for (const [slot, searchedRoots] of this.searchedRootsBySlot) {
|
|
655
755
|
if (slot > minSlot) continue;
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
756
|
+
|
|
757
|
+
// expire messages awaiting an unknown block for these roots. Only roots this slot did a BLOCK search
|
|
758
|
+
// for (blockPeerIds set) have block waits keyed here; skipping the rest avoids deleting a payload wait
|
|
759
|
+
// that a newer slot created for the same root (block/envelope searches share searchedRootsBySlot).
|
|
760
|
+
for (const [rootHex, entry] of searchedRoots) {
|
|
761
|
+
if (entry.blockPeerIds === undefined) continue;
|
|
762
|
+
const messagesByTopic = this.awaitingMessagesByBlockRoot.get(rootHex);
|
|
763
|
+
if (messagesByTopic === undefined) continue;
|
|
764
|
+
let removed = 0;
|
|
765
|
+
for (const messages of messagesByTopic.values()) {
|
|
766
|
+
for (const message of messages) {
|
|
660
767
|
const topicType = message.topic.type;
|
|
661
768
|
this.metrics?.awaitingBlockGossipMessages.reject.inc({
|
|
662
769
|
topic: topicType,
|
|
@@ -668,20 +775,22 @@ export class NetworkProcessor {
|
|
|
668
775
|
);
|
|
669
776
|
// No need to report the dropped job to gossip. It will be eventually pruned from the mcache
|
|
670
777
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
778
|
+
removed += messages.size;
|
|
779
|
+
}
|
|
780
|
+
if (this.awaitingMessagesByBlockRoot.delete(rootHex)) {
|
|
781
|
+
this.awaitingBlockMessageCount -= removed;
|
|
674
782
|
}
|
|
675
783
|
}
|
|
676
|
-
this.unknownBlocksBySlot.delete(slot);
|
|
677
|
-
}
|
|
678
784
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
for (const rootHex of
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
785
|
+
// expire messages awaiting an unknown payload envelope for these roots. Symmetric to the block pass:
|
|
786
|
+
// only roots this slot did an ENVELOPE search for (envelopePeerIds set) have payload waits keyed here.
|
|
787
|
+
for (const [rootHex, entry] of searchedRoots) {
|
|
788
|
+
if (entry.envelopePeerIds === undefined) continue;
|
|
789
|
+
const messagesByTopic = this.awaitingMessagesByPayloadBlockRoot.get(rootHex);
|
|
790
|
+
if (messagesByTopic === undefined) continue;
|
|
791
|
+
let removed = 0;
|
|
792
|
+
for (const messages of messagesByTopic.values()) {
|
|
793
|
+
for (const message of messages) {
|
|
685
794
|
const topicType = message.topic.type;
|
|
686
795
|
this.metrics?.awaitingPayloadGossipMessages.reject.inc({
|
|
687
796
|
topic: topicType,
|
|
@@ -693,12 +802,18 @@ export class NetworkProcessor {
|
|
|
693
802
|
);
|
|
694
803
|
// No need to report the dropped job to gossip. It will be eventually pruned from the mcache
|
|
695
804
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
805
|
+
removed += messages.size;
|
|
806
|
+
}
|
|
807
|
+
if (this.awaitingMessagesByPayloadBlockRoot.delete(rootHex)) {
|
|
808
|
+
this.awaitingPayloadMessageCount -= removed;
|
|
699
809
|
}
|
|
700
810
|
}
|
|
701
|
-
|
|
811
|
+
|
|
812
|
+
this.searchedRootsBySlot.delete(slot);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
for (const slot of this.bufferedRootsBySlot.keys()) {
|
|
816
|
+
if (slot <= minSlot) this.bufferedRootsBySlot.delete(slot);
|
|
702
817
|
}
|
|
703
818
|
};
|
|
704
819
|
|