@lodestar/beacon-node 1.49.0-dev.c9061c6942 → 1.49.0-dev.ca7e252e95
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.js +2 -2
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +4 -2
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +9 -7
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +1 -2
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +0 -5
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/metrics.js +4 -6
- package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/pruneHistory.js +14 -3
- package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +13 -0
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.js +2 -2
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/emitter.d.ts +10 -0
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +4 -0
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/attesterSlashingError.d.ts +4 -1
- package/lib/chain/errors/attesterSlashingError.d.ts.map +1 -1
- package/lib/chain/errors/attesterSlashingError.js +1 -0
- package/lib/chain/errors/attesterSlashingError.js.map +1 -1
- package/lib/chain/errors/payloadAttestation.d.ts +4 -0
- package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
- package/lib/chain/errors/payloadAttestation.js +1 -0
- package/lib/chain/errors/payloadAttestation.js.map +1 -1
- package/lib/chain/errors/proposerSlashingError.d.ts +4 -1
- package/lib/chain/errors/proposerSlashingError.d.ts.map +1 -1
- package/lib/chain/errors/proposerSlashingError.js +1 -0
- package/lib/chain/errors/proposerSlashingError.js.map +1 -1
- package/lib/chain/options.d.ts +0 -4
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +0 -1
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +4 -2
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +6 -6
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +2 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +3 -2
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +1 -2
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +8 -1
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +1 -2
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +2 -2
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/db/beacon.d.ts +1 -2
- package/lib/db/beacon.d.ts.map +1 -1
- package/lib/db/beacon.js +1 -3
- package/lib/db/beacon.js.map +1 -1
- package/lib/db/buckets.d.ts +0 -1
- package/lib/db/buckets.d.ts.map +1 -1
- package/lib/db/buckets.js +1 -1
- package/lib/db/buckets.js.map +1 -1
- package/lib/db/interface.d.ts +1 -2
- package/lib/db/interface.d.ts.map +1 -1
- package/lib/db/repositories/blockArchive.d.ts +5 -0
- package/lib/db/repositories/blockArchive.d.ts.map +1 -1
- package/lib/db/repositories/blockArchive.js +36 -1
- package/lib/db/repositories/blockArchive.js.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/index.d.ts +0 -1
- package/lib/db/repositories/index.d.ts.map +1 -1
- package/lib/db/repositories/index.js +0 -1
- package/lib/db/repositories/index.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +12 -11
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +25 -23
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts +1 -2
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +5 -10
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +16 -1
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +9 -6
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +23 -8
- 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 +16 -5
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipValidatorFn.d.ts +2 -0
- package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
- package/lib/network/processor/gossipValidatorFn.js +88 -7
- package/lib/network/processor/gossipValidatorFn.js.map +1 -1
- package/lib/network/processor/index.d.ts +6 -2
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +62 -24
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/protocols.d.ts.map +1 -1
- package/lib/network/reqresp/protocols.js +19 -5
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/node/nodejs.d.ts +2 -7
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +2 -22
- package/lib/node/nodejs.js.map +1 -1
- package/lib/sync/interface.d.ts +1 -2
- package/lib/sync/interface.d.ts.map +1 -1
- package/lib/sync/options.d.ts +0 -6
- package/lib/sync/options.d.ts.map +1 -1
- package/lib/sync/options.js +0 -2
- package/lib/sync/options.js.map +1 -1
- package/lib/sync/types.d.ts +21 -2
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +22 -2
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +20 -0
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +199 -15
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/shuffle.d.ts +0 -4
- package/lib/util/shuffle.d.ts.map +1 -1
- package/lib/util/shuffle.js +0 -8
- package/lib/util/shuffle.js.map +1 -1
- package/lib/util/sszBytes.d.ts +5 -0
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +13 -1
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +15 -16
- package/src/api/impl/beacon/blocks/index.ts +2 -2
- package/src/api/impl/beacon/pool/index.ts +6 -2
- package/src/api/impl/validator/index.ts +9 -7
- package/src/chain/archiveStore/archiveStore.ts +0 -6
- package/src/chain/archiveStore/historicalState/metrics.ts +4 -7
- package/src/chain/archiveStore/utils/pruneHistory.ts +14 -4
- package/src/chain/blocks/importExecutionPayload.ts +14 -0
- package/src/chain/blocks/index.ts +2 -2
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -1
- package/src/chain/emitter.ts +7 -2
- package/src/chain/errors/attesterSlashingError.ts +3 -1
- package/src/chain/errors/payloadAttestation.ts +2 -0
- package/src/chain/errors/proposerSlashingError.ts +3 -1
- package/src/chain/options.ts +0 -5
- package/src/chain/produceBlock/computeNewStateRoot.ts +9 -2
- package/src/chain/produceBlock/produceBlockBody.ts +17 -6
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +3 -2
- package/src/chain/validation/attesterSlashing.ts +1 -2
- package/src/chain/validation/payloadAttestationMessage.ts +9 -0
- package/src/chain/validation/proposerSlashing.ts +1 -2
- package/src/chain/validatorMonitor.ts +12 -2
- package/src/db/beacon.ts +0 -5
- package/src/db/buckets.ts +1 -1
- package/src/db/interface.ts +0 -3
- package/src/db/repositories/blockArchive.ts +38 -1
- package/src/db/repositories/index.ts +0 -1
- package/src/metrics/metrics/lodestar.ts +34 -26
- package/src/network/gossip/encoding.ts +5 -8
- package/src/network/gossip/gossipsub.ts +19 -2
- package/src/network/gossip/topic.ts +25 -7
- package/src/network/processor/gossipHandlers.ts +18 -5
- package/src/network/processor/gossipValidatorFn.ts +111 -7
- package/src/network/processor/index.ts +81 -24
- package/src/network/reqresp/protocols.ts +31 -6
- package/src/node/nodejs.ts +0 -27
- package/src/sync/interface.ts +1 -2
- package/src/sync/options.ts +0 -8
- package/src/sync/types.ts +24 -5
- package/src/sync/unknownBlock.ts +207 -14
- package/src/util/shuffle.ts +0 -9
- package/src/util/sszBytes.ts +18 -0
- package/lib/chain/archiveStore/utils/updateBackfillRange.d.ts +0 -20
- package/lib/chain/archiveStore/utils/updateBackfillRange.d.ts.map +0 -1
- package/lib/chain/archiveStore/utils/updateBackfillRange.js +0 -40
- package/lib/chain/archiveStore/utils/updateBackfillRange.js.map +0 -1
- package/lib/db/repositories/backfilledRanges.d.ts +0 -18
- package/lib/db/repositories/backfilledRanges.d.ts.map +0 -1
- package/lib/db/repositories/backfilledRanges.js +0 -26
- package/lib/db/repositories/backfilledRanges.js.map +0 -1
- package/lib/sync/backfill/backfill.d.ts +0 -169
- package/lib/sync/backfill/backfill.d.ts.map +0 -1
- package/lib/sync/backfill/backfill.js +0 -686
- package/lib/sync/backfill/backfill.js.map +0 -1
- package/lib/sync/backfill/errors.d.ts +0 -30
- package/lib/sync/backfill/errors.d.ts.map +0 -1
- package/lib/sync/backfill/errors.js +0 -15
- package/lib/sync/backfill/errors.js.map +0 -1
- package/lib/sync/backfill/index.d.ts +0 -2
- package/lib/sync/backfill/index.d.ts.map +0 -1
- package/lib/sync/backfill/index.js +0 -2
- package/lib/sync/backfill/index.js.map +0 -1
- package/lib/sync/backfill/verify.d.ts +0 -18
- package/lib/sync/backfill/verify.d.ts.map +0 -1
- package/lib/sync/backfill/verify.js +0 -36
- package/lib/sync/backfill/verify.js.map +0 -1
- package/src/chain/archiveStore/utils/updateBackfillRange.ts +0 -50
- package/src/db/repositories/backfilledRanges.ts +0 -29
- package/src/sync/backfill/backfill.ts +0 -916
- package/src/sync/backfill/errors.ts +0 -23
- package/src/sync/backfill/index.ts +0 -1
- package/src/sync/backfill/verify.ts +0 -58
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** biome-ignore-all lint/suspicious/noTemplateCurlyInString: The metric templates requires to have `${}` in a normal string */
|
|
2
2
|
import {NotReorgedReason} from "@lodestar/fork-choice";
|
|
3
|
+
import {StateHashTreeRootSource} from "@lodestar/state-transition";
|
|
3
4
|
import {ArchiveStoreTask} from "../../chain/archiveStore/archiveStore.js";
|
|
4
5
|
import {FrequencyStateArchiveStep} from "../../chain/archiveStore/strategies/frequencyStateArchiveStrategy.js";
|
|
5
6
|
import type {LateCanonicalBlockReason} from "../../chain/archiveStore/utils/archiveBlocks.js";
|
|
@@ -25,8 +26,13 @@ import type {FlatFileStoreOperation} from "../../db/flatFileStore/metrics.js";
|
|
|
25
26
|
import {ExecutionPayloadStatus} from "../../execution/index.js";
|
|
26
27
|
import {GossipType} from "../../network/index.js";
|
|
27
28
|
import {CannotAcceptWorkReason, ReprocessRejectReason} from "../../network/processor/index.js";
|
|
28
|
-
import {
|
|
29
|
-
|
|
29
|
+
import {
|
|
30
|
+
DeferredPayloadResult,
|
|
31
|
+
DownloadResult,
|
|
32
|
+
DroppedItemReason,
|
|
33
|
+
FetchResult,
|
|
34
|
+
PendingBlockType,
|
|
35
|
+
} from "../../sync/types.js";
|
|
30
36
|
import {PeerSyncType, RangeSyncType} from "../../sync/utils/remoteSyncType.js";
|
|
31
37
|
import {AllocSource} from "../../util/bufferPool.js";
|
|
32
38
|
import {DataColumnReconstructionCode} from "../../util/dataColumns.js";
|
|
@@ -403,6 +409,15 @@ export function createLodestarMetrics(
|
|
|
403
409
|
labelNames: ["caller"],
|
|
404
410
|
}),
|
|
405
411
|
|
|
412
|
+
// this metrics stay here instead of @lodestar/state-transition in order to prepare
|
|
413
|
+
// for the native zig state-transition in the future
|
|
414
|
+
stateHashTreeRootTime: register.histogram<{source: StateHashTreeRootSource}>({
|
|
415
|
+
name: "lodestar_stfn_hash_tree_root_seconds",
|
|
416
|
+
help: "Time to compute the hash tree root of a post state in seconds",
|
|
417
|
+
buckets: [0.01, 0.05, 0.1, 0.2, 0.3, 0.5],
|
|
418
|
+
labelNames: ["source"],
|
|
419
|
+
}),
|
|
420
|
+
|
|
406
421
|
// BLS verifier thread pool and queue
|
|
407
422
|
|
|
408
423
|
bls: {
|
|
@@ -655,6 +670,16 @@ export function createLodestarMetrics(
|
|
|
655
670
|
help: "Count of payload (execution payload envelope) sync triggers, labeled by their source",
|
|
656
671
|
labelNames: ["source"],
|
|
657
672
|
}),
|
|
673
|
+
deferredPayloadResult: register.counter<{result: DeferredPayloadResult}>({
|
|
674
|
+
name: "lodestar_sync_deferred_payload_result_total",
|
|
675
|
+
help: "Outcome of a slot's deferred optimistic payload searches, by result",
|
|
676
|
+
labelNames: ["result"],
|
|
677
|
+
}),
|
|
678
|
+
deferredPayloadPolls: register.histogram({
|
|
679
|
+
name: "lodestar_sync_deferred_payload_polls_count",
|
|
680
|
+
help: "Poll ticks after PAYLOAD_DUE until a searched payload was imported",
|
|
681
|
+
buckets: [0, 1, 2, 3, 6],
|
|
682
|
+
}),
|
|
658
683
|
pendingBlocks: register.gauge({
|
|
659
684
|
name: "lodestar_sync_unknown_block_pending_blocks_size",
|
|
660
685
|
help: "Current size of UnknownBlockSync pending blocks cache",
|
|
@@ -986,6 +1011,13 @@ export function createLodestarMetrics(
|
|
|
986
1011
|
help: "Count of errors, by error type, while processing execution payload envelopes",
|
|
987
1012
|
labelNames: ["error"],
|
|
988
1013
|
}),
|
|
1014
|
+
executionPayload: {
|
|
1015
|
+
recvToValidation: register.histogram({
|
|
1016
|
+
name: "lodestar_gossip_execution_payload_envelope_received_to_execution_payload_verification_seconds",
|
|
1017
|
+
help: "Time elapsed between execution payload envelope received and execution payload verification",
|
|
1018
|
+
buckets: [0.05, 0.1, 0.25, 0.5, 1, 2, 3, 4, 6, 8],
|
|
1019
|
+
}),
|
|
1020
|
+
},
|
|
989
1021
|
},
|
|
990
1022
|
gossipExecutionPayloadBid: {
|
|
991
1023
|
elapsedTimeTillReceived: register.histogram<{source: OpSource}>({
|
|
@@ -1120,30 +1152,6 @@ export function createLodestarMetrics(
|
|
|
1120
1152
|
help: "The total result of calling notifyForkchoiceUpdate execution engine api",
|
|
1121
1153
|
labelNames: ["result"],
|
|
1122
1154
|
}),
|
|
1123
|
-
backfillSync: {
|
|
1124
|
-
backfilledTillSlot: register.gauge({
|
|
1125
|
-
name: "lodestar_backfill_till_slot",
|
|
1126
|
-
help: "Current lowest backfilled slot",
|
|
1127
|
-
}),
|
|
1128
|
-
prevFinOrWsSlot: register.gauge({
|
|
1129
|
-
name: "lodestar_backfill_prev_fin_or_ws_slot",
|
|
1130
|
-
help: "Slot of previous finalized or wsCheckpoint block to be validated",
|
|
1131
|
-
}),
|
|
1132
|
-
totalBlocks: register.gauge<{method: BackfillSyncMethod}>({
|
|
1133
|
-
name: "lodestar_backfill_sync_blocks_total",
|
|
1134
|
-
help: "Total amount of backfilled blocks",
|
|
1135
|
-
labelNames: ["method"],
|
|
1136
|
-
}),
|
|
1137
|
-
errors: register.gauge({
|
|
1138
|
-
name: "lodestar_backfill_sync_errors_total",
|
|
1139
|
-
help: "Total number of errors while backfilling",
|
|
1140
|
-
}),
|
|
1141
|
-
status: register.gauge({
|
|
1142
|
-
name: "lodestar_backfill_sync_status",
|
|
1143
|
-
help: "Current backfill syncing status: [Aborted, Pending, Syncing, Completed]",
|
|
1144
|
-
}),
|
|
1145
|
-
},
|
|
1146
|
-
|
|
1147
1155
|
opPool: {
|
|
1148
1156
|
aggregatedAttestationPool: {
|
|
1149
1157
|
size: register.gauge({
|
|
@@ -8,7 +8,7 @@ import {ForkName} from "@lodestar/params";
|
|
|
8
8
|
import {intToBytes} from "@lodestar/utils";
|
|
9
9
|
import {MESSAGE_DOMAIN_VALID_SNAPPY} from "./constants.js";
|
|
10
10
|
import {Eth2GossipsubMetrics} from "./metrics.js";
|
|
11
|
-
import {GossipTopicCache
|
|
11
|
+
import {GossipTopicCache} from "./topic.js";
|
|
12
12
|
|
|
13
13
|
// Load WASM
|
|
14
14
|
const xxhash = await xxhashFactory();
|
|
@@ -97,7 +97,6 @@ export function msgIdFn(gossipTopicCache: GossipTopicCache, msg: Message): Uint8
|
|
|
97
97
|
export class DataTransformSnappy implements DataTransform {
|
|
98
98
|
constructor(
|
|
99
99
|
private readonly gossipTopicCache: GossipTopicCache,
|
|
100
|
-
private readonly maxPayloadSize: number,
|
|
101
100
|
private readonly metrics: Eth2GossipsubMetrics | null
|
|
102
101
|
) {}
|
|
103
102
|
|
|
@@ -112,12 +111,11 @@ export class DataTransformSnappy implements DataTransform {
|
|
|
112
111
|
const uncompressedDataLength = snappyWasm.decompress_len(data);
|
|
113
112
|
|
|
114
113
|
const topic = this.gossipTopicCache.getTopic(topicStr);
|
|
115
|
-
const
|
|
116
|
-
const maxSize = getGossipSSZMaxSize(topic, this.maxPayloadSize, sszType);
|
|
114
|
+
const {minSize, maxSize} = this.gossipTopicCache.getTypeSizes(topicStr);
|
|
117
115
|
this.metrics?.dataTransform.inbound.inc({type: topic.type});
|
|
118
116
|
|
|
119
|
-
if (uncompressedDataLength <
|
|
120
|
-
throw Error(`ssz_snappy decoded data length ${uncompressedDataLength} < ${
|
|
117
|
+
if (uncompressedDataLength < minSize) {
|
|
118
|
+
throw Error(`ssz_snappy decoded data length ${uncompressedDataLength} < ${minSize}`);
|
|
121
119
|
}
|
|
122
120
|
if (uncompressedDataLength > maxSize) {
|
|
123
121
|
throw Error(`ssz_snappy decoded data length ${uncompressedDataLength} > ${maxSize}`);
|
|
@@ -136,8 +134,7 @@ export class DataTransformSnappy implements DataTransform {
|
|
|
136
134
|
*/
|
|
137
135
|
outboundTransform(topicStr: string, data: Uint8Array): Uint8Array {
|
|
138
136
|
const topic = this.gossipTopicCache.getTopic(topicStr);
|
|
139
|
-
const
|
|
140
|
-
const maxSize = getGossipSSZMaxSize(topic, this.maxPayloadSize, sszType);
|
|
137
|
+
const {maxSize} = this.gossipTopicCache.getTypeSizes(topicStr);
|
|
141
138
|
this.metrics?.dataTransform.outbound.inc({type: topic.type});
|
|
142
139
|
if (data.length > maxSize) {
|
|
143
140
|
throw Error(`ssz_snappy encoded data length ${data.length} > ${maxSize}`);
|
|
@@ -14,7 +14,7 @@ import {peerIdFromString} from "@libp2p/peer-id";
|
|
|
14
14
|
import {type Multiaddr, multiaddr} from "@multiformats/multiaddr";
|
|
15
15
|
import {ENR} from "@chainsafe/enr";
|
|
16
16
|
import {routes} from "@lodestar/api";
|
|
17
|
-
import {BeaconConfig, ForkBoundary} from "@lodestar/config";
|
|
17
|
+
import {BeaconConfig, ChainConfig, ForkBoundary} from "@lodestar/config";
|
|
18
18
|
import {
|
|
19
19
|
ATTESTATION_SUBNET_COUNT,
|
|
20
20
|
MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE,
|
|
@@ -47,6 +47,22 @@ const GOSSIPSUB_HEARTBEAT_INTERVAL = 0.7 * 1000;
|
|
|
47
47
|
|
|
48
48
|
const MAX_OUTBOUND_BUFFER_SIZE = 2 ** 24; // 16MB
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Snappy worst-case compressed length for a payload of `n` bytes
|
|
52
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-beta.0/specs/phase0/p2p-interface.md#max_compressed_len
|
|
53
|
+
*/
|
|
54
|
+
function maxCompressedLen(n: number): number {
|
|
55
|
+
return 32 + n + Math.floor(n / 6);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Max size of an inbound gossipsub RPC frame, including all bundled messages and control
|
|
60
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-beta.0/specs/phase0/p2p-interface.md#max_message_size
|
|
61
|
+
*/
|
|
62
|
+
function getMaxInboundDataLength(config: Pick<ChainConfig, "MAX_PAYLOAD_SIZE">): number {
|
|
63
|
+
return Math.max(maxCompressedLen(config.MAX_PAYLOAD_SIZE) + 1024, 1024 * 1024);
|
|
64
|
+
}
|
|
65
|
+
|
|
50
66
|
export type Eth2Context = {
|
|
51
67
|
activeValidatorCount: number;
|
|
52
68
|
currentSlot: number;
|
|
@@ -168,7 +184,7 @@ export class Eth2Gossipsub {
|
|
|
168
184
|
fastMsgIdFn: fastMsgIdFn,
|
|
169
185
|
msgIdFn: msgIdFn.bind(msgIdFn, gossipTopicCache),
|
|
170
186
|
msgIdToStrFn: msgIdToStrFn,
|
|
171
|
-
dataTransform: new DataTransformSnappy(gossipTopicCache,
|
|
187
|
+
dataTransform: new DataTransformSnappy(gossipTopicCache, metrics),
|
|
172
188
|
metricsRegister: metricsRegister as MetricsRegister | null,
|
|
173
189
|
metricsTopicStrToLabel: metricsRegister
|
|
174
190
|
? getMetricsTopicStrToLabel(networkConfig, {disableLightClientServer: opts.disableLightClientServer ?? false})
|
|
@@ -176,6 +192,7 @@ export class Eth2Gossipsub {
|
|
|
176
192
|
asyncValidation: true,
|
|
177
193
|
|
|
178
194
|
maxOutboundBufferSize: MAX_OUTBOUND_BUFFER_SIZE,
|
|
195
|
+
maxInboundDataLength: getMaxInboundDataLength(config),
|
|
179
196
|
// serialize message once and send to all peers when publishing
|
|
180
197
|
batchPublish: true,
|
|
181
198
|
// if this is false, only publish to mesh peers. If there is not enough GOSSIP_D mesh peers,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {type CompositeTypeAny} from "@chainsafe/ssz";
|
|
2
|
-
import {ForkDigestContext} from "@lodestar/config";
|
|
2
|
+
import {BeaconConfig, ChainForkConfig, ForkDigestContext} from "@lodestar/config";
|
|
3
3
|
import {
|
|
4
4
|
ATTESTATION_SUBNET_COUNT,
|
|
5
5
|
ForkName,
|
|
@@ -10,32 +10,47 @@ import {
|
|
|
10
10
|
isForkPostFulu,
|
|
11
11
|
isForkPostGloas,
|
|
12
12
|
} from "@lodestar/params";
|
|
13
|
+
import {TypeSizes} from "@lodestar/reqresp";
|
|
13
14
|
import {Attestation, SingleAttestation, ssz, sszTypesFor} from "@lodestar/types";
|
|
14
15
|
import {GossipAction, GossipActionError, GossipErrorCode} from "../../chain/errors/gossipValidation.js";
|
|
16
|
+
import {computeMaxGloasDataColumnSidecarSize} from "../../util/sszBytes.js";
|
|
15
17
|
import {NetworkConfig} from "../networkConfig.js";
|
|
16
18
|
import {DEFAULT_ENCODING} from "./constants.js";
|
|
17
19
|
import {GossipEncoding, GossipTopic, GossipTopicTypeMap, GossipType, SSZTypeOfGossipTopic} from "./interface.js";
|
|
18
20
|
|
|
19
21
|
export interface IGossipTopicCache {
|
|
20
22
|
getTopic(topicStr: string): GossipTopic;
|
|
23
|
+
getTypeSizes(topicStr: string): TypeSizes;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
export class GossipTopicCache implements IGossipTopicCache {
|
|
24
27
|
private topicsByTopicStr = new Map<string, Required<GossipTopic>>();
|
|
28
|
+
private typeSizesByTopicStr = new Map<string, TypeSizes>();
|
|
25
29
|
|
|
26
|
-
constructor(private readonly
|
|
30
|
+
constructor(private readonly config: BeaconConfig) {}
|
|
27
31
|
|
|
28
32
|
/** Returns cached GossipTopic, otherwise attempts to parse it from the str */
|
|
29
33
|
getTopic(topicStr: string): GossipTopic {
|
|
30
34
|
let topic = this.topicsByTopicStr.get(topicStr);
|
|
31
35
|
if (topic === undefined) {
|
|
32
|
-
topic = parseGossipTopic(this.
|
|
36
|
+
topic = parseGossipTopic(this.config, topicStr);
|
|
33
37
|
// TODO: Consider just throwing here. We should only receive messages from known subscribed topics
|
|
34
38
|
this.topicsByTopicStr.set(topicStr, topic);
|
|
35
39
|
}
|
|
36
40
|
return topic;
|
|
37
41
|
}
|
|
38
42
|
|
|
43
|
+
getTypeSizes(topicStr: string): TypeSizes {
|
|
44
|
+
let typeSizes = this.typeSizesByTopicStr.get(topicStr);
|
|
45
|
+
if (typeSizes === undefined) {
|
|
46
|
+
const topic = this.getTopic(topicStr);
|
|
47
|
+
const sszType = getGossipSSZType(topic);
|
|
48
|
+
typeSizes = {minSize: sszType.minSize, maxSize: getGossipSSZMaxSize(topic, this.config, sszType)};
|
|
49
|
+
this.typeSizesByTopicStr.set(topicStr, typeSizes);
|
|
50
|
+
}
|
|
51
|
+
return typeSizes;
|
|
52
|
+
}
|
|
53
|
+
|
|
39
54
|
/** Returns cached GossipTopic, otherwise returns undefined */
|
|
40
55
|
getKnownTopic(topicStr: string): GossipTopic | undefined {
|
|
41
56
|
return this.topicsByTopicStr.get(topicStr);
|
|
@@ -133,11 +148,14 @@ export function getGossipSSZType(topic: GossipTopic) {
|
|
|
133
148
|
}
|
|
134
149
|
|
|
135
150
|
/**
|
|
136
|
-
* Return the maximum uncompressed SSZ byte length
|
|
137
|
-
* or MAX_PAYLOAD_SIZE, whichever is smaller.
|
|
151
|
+
* Return the maximum uncompressed SSZ byte length allowed by the type and configured network bounds.
|
|
138
152
|
*/
|
|
139
|
-
export function getGossipSSZMaxSize(topic: GossipTopic,
|
|
140
|
-
|
|
153
|
+
export function getGossipSSZMaxSize(topic: GossipTopic, config: ChainForkConfig, sszType: CompositeTypeAny): number {
|
|
154
|
+
const maxSize = Math.min(sszType.maxSize, config.MAX_PAYLOAD_SIZE);
|
|
155
|
+
if (isForkPostGloas(topic.boundary.fork) && topic.type === GossipType.data_column_sidecar) {
|
|
156
|
+
return Math.min(maxSize, computeMaxGloasDataColumnSidecarSize(config));
|
|
157
|
+
}
|
|
158
|
+
return maxSize;
|
|
141
159
|
}
|
|
142
160
|
|
|
143
161
|
/**
|
|
@@ -244,8 +244,20 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
244
244
|
|
|
245
245
|
// IGNORE means the block is acceptable (e.g. FUTURE_SLOT, ALREADY_KNOWN), just not propagated.
|
|
246
246
|
// Keep the optimistically-added cache entries; they are pruned on finalization. Only REJECT
|
|
247
|
-
// (provably invalid)
|
|
247
|
+
// (provably invalid), unexpected errors and repeat proposals that are not imported prune.
|
|
248
248
|
if (e.action === GossipAction.IGNORE) {
|
|
249
|
+
// Only a signature-verified sibling is imported by the beacon_block handler, any other repeat proposal
|
|
250
|
+
// is dropped from the caches and re-downloaded by sync if it ever becomes relevant. Its signature was not
|
|
251
|
+
// verified, so only its own entry is removed, never its claimed ancestors
|
|
252
|
+
if (
|
|
253
|
+
e.type.code === BlockErrorCode.REPEAT_PROPOSAL &&
|
|
254
|
+
!chain.seenBlockProposers.hasBlockRoot(slot, signedBlock.message.proposerIndex, blockRootHex)
|
|
255
|
+
) {
|
|
256
|
+
chain.seenBlockInputCache.remove(blockRootHex);
|
|
257
|
+
if (isForkPostGloas(fork)) {
|
|
258
|
+
chain.seenPayloadEnvelopeInputCache.remove(blockRootHex);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
249
261
|
throw e;
|
|
250
262
|
}
|
|
251
263
|
|
|
@@ -258,10 +270,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
258
270
|
}
|
|
259
271
|
|
|
260
272
|
// REJECT or unexpected (non-BlockGossipError) error: drop the optimistically-added entries from
|
|
261
|
-
// both caches, keeping them consistent.
|
|
262
|
-
chain.seenBlockInputCache.
|
|
273
|
+
// both caches, keeping them consistent. The block may carry any parent root, so only its own entry is removed
|
|
274
|
+
chain.seenBlockInputCache.remove(blockRootHex);
|
|
263
275
|
if (isForkPostGloas(fork)) {
|
|
264
|
-
chain.seenPayloadEnvelopeInputCache.
|
|
276
|
+
chain.seenPayloadEnvelopeInputCache.remove(blockRootHex);
|
|
265
277
|
}
|
|
266
278
|
throw e;
|
|
267
279
|
} finally {
|
|
@@ -738,7 +750,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
738
750
|
if (
|
|
739
751
|
e instanceof BlockGossipError &&
|
|
740
752
|
e.type.code === BlockErrorCode.REPEAT_PROPOSAL &&
|
|
741
|
-
//
|
|
753
|
+
// Only a signature-verified sibling recorded in the seen cache is imported. The cache holds at most two
|
|
754
|
+
// roots per proposer and slot, which bounds full imports over gossip to one alternate
|
|
742
755
|
chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root)
|
|
743
756
|
) {
|
|
744
757
|
// blockInput was optimistically seeded in validateBeaconBlock and retained on IGNORE
|
|
@@ -1,24 +1,122 @@
|
|
|
1
1
|
import {TopicValidatorResult} from "@libp2p/gossipsub";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {Logger} from "@lodestar/utils";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
AttestationError,
|
|
6
|
+
AttestationErrorCode,
|
|
7
|
+
AttesterSlashingErrorCode,
|
|
8
|
+
BlobSidecarErrorCode,
|
|
9
|
+
BlockErrorCode,
|
|
10
|
+
BlsToExecutionChangeErrorCode,
|
|
11
|
+
DataColumnSidecarErrorCode,
|
|
12
|
+
ExecutionPayloadBidErrorCode,
|
|
13
|
+
ExecutionPayloadEnvelopeErrorCode,
|
|
14
|
+
GossipAction,
|
|
15
|
+
GossipActionError,
|
|
16
|
+
PayloadAttestationErrorCode,
|
|
17
|
+
ProposerPreferencesErrorCode,
|
|
18
|
+
ProposerSlashingErrorCode,
|
|
19
|
+
SyncCommitteeErrorCode,
|
|
20
|
+
VoluntaryExitErrorCode,
|
|
21
|
+
} from "../../chain/errors/index.js";
|
|
5
22
|
import {Metrics} from "../../metrics/index.js";
|
|
23
|
+
import {INetworkCore} from "../core/index.js";
|
|
6
24
|
import {
|
|
7
25
|
BatchGossipHandlerFn,
|
|
8
26
|
GossipHandlerFn,
|
|
9
27
|
GossipHandlers,
|
|
10
28
|
GossipMessageInfo,
|
|
29
|
+
GossipType,
|
|
11
30
|
GossipValidatorBatchFn,
|
|
12
31
|
GossipValidatorFn,
|
|
13
32
|
} from "../gossip/interface.js";
|
|
33
|
+
import {PeerAction} from "../peers/index.js";
|
|
14
34
|
import {prettyPrintPeerIdStr} from "../util.js";
|
|
15
35
|
|
|
16
36
|
export type ValidatorFnModules = {
|
|
17
37
|
config: ChainForkConfig;
|
|
18
38
|
logger: Logger;
|
|
19
39
|
metrics: Metrics | null;
|
|
40
|
+
core: INetworkCore;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type RejectPeerActionRule = {default: PeerAction; byCode?: Record<string, PeerAction>};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* PeerAction mapping based on the topic and specific codes.
|
|
47
|
+
* Invalid signatures are Fatal on every topic.
|
|
48
|
+
*/
|
|
49
|
+
const gossipRejectPeerAction: Record<GossipType, RejectPeerActionRule> = {
|
|
50
|
+
[GossipType.beacon_block]: {
|
|
51
|
+
default: PeerAction.LowToleranceError,
|
|
52
|
+
byCode: {[BlockErrorCode.PROPOSAL_SIGNATURE_INVALID]: PeerAction.Fatal},
|
|
53
|
+
},
|
|
54
|
+
[GossipType.blob_sidecar]: {
|
|
55
|
+
default: PeerAction.LowToleranceError,
|
|
56
|
+
byCode: {[BlobSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID]: PeerAction.Fatal},
|
|
57
|
+
},
|
|
58
|
+
[GossipType.data_column_sidecar]: {
|
|
59
|
+
default: PeerAction.LowToleranceError,
|
|
60
|
+
byCode: {[DataColumnSidecarErrorCode.PROPOSAL_SIGNATURE_INVALID]: PeerAction.Fatal},
|
|
61
|
+
},
|
|
62
|
+
[GossipType.execution_payload]: {
|
|
63
|
+
default: PeerAction.LowToleranceError,
|
|
64
|
+
byCode: {[ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
65
|
+
},
|
|
66
|
+
[GossipType.beacon_aggregate_and_proof]: {
|
|
67
|
+
default: PeerAction.MidToleranceError,
|
|
68
|
+
byCode: {[AttestationErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
69
|
+
},
|
|
70
|
+
[GossipType.beacon_attestation]: {
|
|
71
|
+
default: PeerAction.MidToleranceError,
|
|
72
|
+
byCode: {[AttestationErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
73
|
+
},
|
|
74
|
+
[GossipType.sync_committee_contribution_and_proof]: {
|
|
75
|
+
default: PeerAction.MidToleranceError,
|
|
76
|
+
byCode: {[SyncCommitteeErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
77
|
+
},
|
|
78
|
+
[GossipType.sync_committee]: {
|
|
79
|
+
default: PeerAction.MidToleranceError,
|
|
80
|
+
byCode: {[SyncCommitteeErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
81
|
+
},
|
|
82
|
+
[GossipType.payload_attestation_message]: {
|
|
83
|
+
default: PeerAction.MidToleranceError,
|
|
84
|
+
byCode: {[PayloadAttestationErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
85
|
+
},
|
|
86
|
+
[GossipType.execution_payload_bid]: {
|
|
87
|
+
default: PeerAction.HighToleranceError,
|
|
88
|
+
byCode: {[ExecutionPayloadBidErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
89
|
+
},
|
|
90
|
+
[GossipType.proposer_preferences]: {
|
|
91
|
+
default: PeerAction.HighToleranceError,
|
|
92
|
+
byCode: {[ProposerPreferencesErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
93
|
+
},
|
|
94
|
+
[GossipType.voluntary_exit]: {
|
|
95
|
+
default: PeerAction.HighToleranceError,
|
|
96
|
+
byCode: {[VoluntaryExitErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
97
|
+
},
|
|
98
|
+
[GossipType.bls_to_execution_change]: {
|
|
99
|
+
default: PeerAction.HighToleranceError,
|
|
100
|
+
byCode: {[BlsToExecutionChangeErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
101
|
+
},
|
|
102
|
+
[GossipType.proposer_slashing]: {
|
|
103
|
+
default: PeerAction.HighToleranceError,
|
|
104
|
+
byCode: {[ProposerSlashingErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
105
|
+
},
|
|
106
|
+
[GossipType.attester_slashing]: {
|
|
107
|
+
default: PeerAction.HighToleranceError,
|
|
108
|
+
byCode: {[AttesterSlashingErrorCode.INVALID_SIGNATURE]: PeerAction.Fatal},
|
|
109
|
+
},
|
|
110
|
+
// light client validators only throw IGNORE
|
|
111
|
+
[GossipType.light_client_finality_update]: {default: PeerAction.HighToleranceError},
|
|
112
|
+
[GossipType.light_client_optimistic_update]: {default: PeerAction.HighToleranceError},
|
|
20
113
|
};
|
|
21
114
|
|
|
115
|
+
function rejectPeerAction(type: GossipType, code: string): PeerAction {
|
|
116
|
+
const rule = gossipRejectPeerAction[type];
|
|
117
|
+
return rule.byCode?.[code] ?? rule.default;
|
|
118
|
+
}
|
|
119
|
+
|
|
22
120
|
/**
|
|
23
121
|
* Similar to getGossipValidatorFn but return a function to accept a batch of beacon_attestation messages
|
|
24
122
|
* with the same attestation data
|
|
@@ -27,7 +125,7 @@ export function getGossipValidatorBatchFn(
|
|
|
27
125
|
gossipHandlers: GossipHandlers,
|
|
28
126
|
modules: ValidatorFnModules
|
|
29
127
|
): GossipValidatorBatchFn {
|
|
30
|
-
const {logger, metrics} = modules;
|
|
128
|
+
const {logger, metrics, core} = modules;
|
|
31
129
|
|
|
32
130
|
return async function gossipValidatorBatchFn(messageInfos: GossipMessageInfo[]) {
|
|
33
131
|
// all messageInfos have same topic type
|
|
@@ -69,16 +167,19 @@ export function getGossipValidatorBatchFn(
|
|
|
69
167
|
// only beacon_attestation topic is validated in batch
|
|
70
168
|
metrics?.networkProcessor.gossipAttestationIgnoreByReason.inc({reason: e.type.code});
|
|
71
169
|
return TopicValidatorResult.Ignore;
|
|
72
|
-
case GossipAction.REJECT:
|
|
170
|
+
case GossipAction.REJECT: {
|
|
73
171
|
metrics?.networkProcessor.gossipValidationReject.inc({topic: type});
|
|
74
172
|
// only beacon_attestation topic is validated in batch
|
|
75
173
|
metrics?.networkProcessor.gossipAttestationRejectByReason.inc({reason: e.type.code});
|
|
174
|
+
const peerAction = rejectPeerAction(type, e.type.code);
|
|
175
|
+
core.reportPeer(propagationSource, peerAction, e.type.code);
|
|
76
176
|
logger.debug(
|
|
77
177
|
`Gossip validation ${type} rejected`,
|
|
78
|
-
{
|
|
178
|
+
{peer: propagationSource, clientAgent, clientVersion, peerAction},
|
|
79
179
|
e
|
|
80
180
|
);
|
|
81
181
|
return TopicValidatorResult.Reject;
|
|
182
|
+
}
|
|
82
183
|
}
|
|
83
184
|
});
|
|
84
185
|
} catch (e) {
|
|
@@ -108,7 +209,7 @@ export function getGossipValidatorBatchFn(
|
|
|
108
209
|
* @see getGossipHandlers for reasoning on why GossipHandlerFn are used for gossip validation.
|
|
109
210
|
*/
|
|
110
211
|
export function getGossipValidatorFn(gossipHandlers: GossipHandlers, modules: ValidatorFnModules): GossipValidatorFn {
|
|
111
|
-
const {logger, metrics} = modules;
|
|
212
|
+
const {logger, metrics, core} = modules;
|
|
112
213
|
|
|
113
214
|
return async function gossipValidatorFn({
|
|
114
215
|
topic,
|
|
@@ -155,14 +256,17 @@ export function getGossipValidatorFn(gossipHandlers: GossipHandlers, modules: Va
|
|
|
155
256
|
metrics?.networkProcessor.gossipValidationIgnore.inc({topic: type});
|
|
156
257
|
return TopicValidatorResult.Ignore;
|
|
157
258
|
|
|
158
|
-
case GossipAction.REJECT:
|
|
259
|
+
case GossipAction.REJECT: {
|
|
159
260
|
metrics?.networkProcessor.gossipValidationReject.inc({topic: type});
|
|
261
|
+
const peerAction = rejectPeerAction(type, e.type.code);
|
|
262
|
+
core.reportPeer(propagationSource, peerAction, e.type.code);
|
|
160
263
|
logger.debug(
|
|
161
264
|
`Gossip validation ${type} rejected`,
|
|
162
|
-
{
|
|
265
|
+
{peer: propagationSource, clientAgent, clientVersion, peerAction},
|
|
163
266
|
e
|
|
164
267
|
);
|
|
165
268
|
return TopicValidatorResult.Reject;
|
|
269
|
+
}
|
|
166
270
|
}
|
|
167
271
|
}
|
|
168
272
|
};
|