@lodestar/beacon-node 1.48.0-dev.f22c5ce63e → 1.48.0-dev.ff9749be2c
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 -11
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +14 -0
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/config/index.d.ts.map +1 -1
- package/lib/api/impl/config/index.js +4 -1
- package/lib/api/impl/config/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 +5 -1
- 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 +9 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +68 -38
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts +5 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +12 -18
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/index.d.ts +8 -4
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +83 -17
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +8 -0
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/types.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 +26 -11
- 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 +11 -5
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +129 -75
- 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 +14 -9
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +0 -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/executionPayloadBid.d.ts +4 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +1 -0
- package/lib/chain/errors/executionPayloadBid.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/errors/gossipValidation.d.ts +2 -1
- package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
- package/lib/chain/errors/gossipValidation.js +1 -0
- package/lib/chain/errors/gossipValidation.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +2 -0
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +4 -4
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/lightClient/index.d.ts +3 -3
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +21 -23
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/lightClient/proofs.d.ts +2 -1
- package/lib/chain/lightClient/proofs.d.ts.map +1 -1
- package/lib/chain/lightClient/proofs.js +5 -1
- package/lib/chain/lightClient/proofs.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +16 -14
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +4 -2
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +57 -72
- 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 +27 -55
- 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/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +56 -40
- package/lib/chain/validation/executionPayloadBid.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/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +5 -6
- package/lib/chain/validation/payloadAttestationMessage.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/builder/validateBid.d.ts.map +1 -1
- package/lib/execution/builder/validateBid.js +8 -5
- package/lib/execution/builder/validateBid.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 +22 -3
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +60 -6
- 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/libp2p/index.d.ts +9 -1
- package/lib/network/libp2p/index.d.ts.map +1 -1
- package/lib/network/libp2p/index.js +23 -0
- package/lib/network/libp2p/index.js.map +1 -1
- package/lib/network/network.js +2 -2
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +388 -285
- 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 +254 -114
- 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/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +24 -1
- package/lib/sync/range/range.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 -14
- package/src/api/impl/beacon/state/utils.ts +15 -0
- package/src/api/impl/config/index.ts +4 -1
- package/src/api/impl/validator/index.ts +44 -43
- package/src/chain/archiveStore/archiveStore.ts +12 -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 +73 -42
- package/src/chain/blocks/importBlock.ts +25 -20
- package/src/chain/blocks/index.ts +120 -23
- package/src/chain/blocks/types.ts +9 -0
- package/src/chain/blocks/utils/chainSegment.ts +26 -12
- package/src/chain/blocks/writeBlockInputToDb.ts +10 -17
- package/src/chain/chain.ts +153 -84
- package/src/chain/emitter.ts +1 -1
- package/src/chain/errors/blockError.ts +19 -10
- package/src/chain/errors/dataColumnSidecarError.ts +24 -8
- package/src/chain/errors/executionPayloadBid.ts +2 -0
- package/src/chain/errors/executionPayloadEnvelope.ts +14 -11
- package/src/chain/errors/gossipValidation.ts +1 -0
- package/src/chain/forkChoice/index.ts +2 -0
- package/src/chain/interface.ts +4 -4
- package/src/chain/lightClient/index.ts +32 -36
- package/src/chain/lightClient/proofs.ts +10 -0
- package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
- package/src/chain/prepareNextSlot.ts +21 -17
- package/src/chain/produceBlock/produceBlockBody.ts +62 -79
- package/src/chain/validation/block.ts +27 -72
- package/src/chain/validation/dataColumnSidecar.ts +47 -14
- package/src/chain/validation/executionPayloadBid.ts +62 -44
- package/src/chain/validation/executionPayloadEnvelope.ts +10 -37
- package/src/chain/validation/payloadAttestationMessage.ts +8 -9
- 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/builder/validateBid.ts +10 -6
- package/src/execution/engine/mock.ts +4 -1
- package/src/metrics/metrics/lodestar.ts +63 -6
- 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/libp2p/index.ts +28 -1
- package/src/network/network.ts +2 -2
- package/src/network/processor/gossipHandlers.ts +500 -355
- package/src/network/processor/index.ts +287 -165
- 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/sync/range/range.ts +23 -1
- package/src/util/sszBytes.ts +1 -1
|
@@ -3,7 +3,7 @@ import { PayloadStatus } from "@lodestar/fork-choice";
|
|
|
3
3
|
import { ForkSeq, NUMBER_OF_COLUMNS, isForkPostElectra, isForkPostGloas, } from "@lodestar/params";
|
|
4
4
|
import { computeTimeAtSlot } from "@lodestar/state-transition";
|
|
5
5
|
import { isGloasDataColumnSidecar, ssz, sszTypesFor, } from "@lodestar/types";
|
|
6
|
-
import { LogLevel,
|
|
6
|
+
import { LogLevel, toHex, toRootHex } from "@lodestar/utils";
|
|
7
7
|
import { BlockInputSource, isBlockInputColumns, } from "../../chain/blocks/blockInput/index.js";
|
|
8
8
|
import { PayloadError, PayloadErrorCode } from "../../chain/blocks/importExecutionPayload.js";
|
|
9
9
|
import { PayloadEnvelopeInputSource } from "../../chain/blocks/payloadEnvelopeInput/index.js";
|
|
@@ -22,6 +22,7 @@ import { validateGossipProposerPreferences } from "../../chain/validation/propos
|
|
|
22
22
|
import { OpSource } from "../../chain/validatorMonitor.js";
|
|
23
23
|
import { kzgCommitmentToVersionedHash } from "../../util/blobs.js";
|
|
24
24
|
import { getBlobKzgCommitments, getDataColumnSidecarSlot } from "../../util/dataColumns.js";
|
|
25
|
+
import { callInNextEventLoop } from "../../util/eventLoop.js";
|
|
25
26
|
import { GossipType, } from "../gossip/interface.js";
|
|
26
27
|
import { sszDeserialize } from "../gossip/topic.js";
|
|
27
28
|
import { PeerAction } from "../peers/index.js";
|
|
@@ -54,7 +55,6 @@ function getSequentialHandlers(modules, options) {
|
|
|
54
55
|
const slot = signedBlock.message.slot;
|
|
55
56
|
const forkTypes = config.getForkTypes(slot);
|
|
56
57
|
const blockRootHex = toRootHex(forkTypes.BeaconBlock.hashTreeRoot(signedBlock.message));
|
|
57
|
-
const blockShortHex = prettyBytes(blockRootHex);
|
|
58
58
|
const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec);
|
|
59
59
|
const recvToValLatency = Date.now() / 1000 - seenTimestampSec;
|
|
60
60
|
// always set block to seen cache for all forks so that we don't need to download it
|
|
@@ -62,6 +62,7 @@ function getSequentialHandlers(modules, options) {
|
|
|
62
62
|
// tracked in https://github.com/ChainSafe/lodestar/issues/7957
|
|
63
63
|
const logCtx = {
|
|
64
64
|
slot,
|
|
65
|
+
root: blockRootHex,
|
|
65
66
|
currentSlot: chain.clock.currentSlot,
|
|
66
67
|
peerId: peerIdStr,
|
|
67
68
|
delaySec,
|
|
@@ -113,7 +114,7 @@ function getSequentialHandlers(modules, options) {
|
|
|
113
114
|
}
|
|
114
115
|
catch (e) {
|
|
115
116
|
if (e instanceof BlockGossipError) {
|
|
116
|
-
logger.debug("Gossip block has error", { slot, root:
|
|
117
|
+
logger.debug("Gossip block has error", { slot, root: blockRootHex, code: e.type.code });
|
|
117
118
|
if ((e.type.code === BlockErrorCode.PARENT_BLOCK_UNKNOWN ||
|
|
118
119
|
e.type.code === BlockErrorCode.PARENT_PAYLOAD_UNKNOWN) &&
|
|
119
120
|
blockInput) {
|
|
@@ -131,7 +132,7 @@ function getSequentialHandlers(modules, options) {
|
|
|
131
132
|
if (e.action === GossipAction.IGNORE) {
|
|
132
133
|
throw e;
|
|
133
134
|
}
|
|
134
|
-
chain.persistInvalidSszValue(forkTypes.SignedBeaconBlock, signedBlock, `gossip_reject_slot_${slot}
|
|
135
|
+
chain.persistInvalidSszValue(forkTypes.SignedBeaconBlock, signedBlock, `gossip_reject_slot_${slot}`, blockRootHex);
|
|
135
136
|
}
|
|
136
137
|
// REJECT or unexpected (non-BlockGossipError) error: drop the optimistically-added entries from
|
|
137
138
|
// both caches, keeping them consistent.
|
|
@@ -155,7 +156,6 @@ function getSequentialHandlers(modules, options) {
|
|
|
155
156
|
const slot = blobBlockHeader.slot;
|
|
156
157
|
const fork = config.getForkName(slot);
|
|
157
158
|
const blockRootHex = toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(blobBlockHeader));
|
|
158
|
-
const blockShortHex = prettyBytes(blockRootHex);
|
|
159
159
|
const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec);
|
|
160
160
|
const recvToValLatency = Date.now() / 1000 - seenTimestampSec;
|
|
161
161
|
try {
|
|
@@ -204,7 +204,7 @@ function getSequentialHandlers(modules, options) {
|
|
|
204
204
|
if (e instanceof BlobSidecarGossipError) {
|
|
205
205
|
// Don't trigger this yet if full block and blobs haven't arrived yet
|
|
206
206
|
if (e.type.code === BlobSidecarErrorCode.PARENT_UNKNOWN) {
|
|
207
|
-
logger.debug("Gossip blob has error", { slot, root:
|
|
207
|
+
logger.debug("Gossip blob has error", { slot, root: blockRootHex, code: e.type.code });
|
|
208
208
|
// no need to trigger `unknownBlockParent` event here, as we already did it in `validateBeaconBlock()`
|
|
209
209
|
//
|
|
210
210
|
// TODO(fulu): is this note above correct? Could have random blob that we see that could trigger
|
|
@@ -509,7 +509,7 @@ function getSequentialHandlers(modules, options) {
|
|
|
509
509
|
logLevel = LogLevel.error;
|
|
510
510
|
}
|
|
511
511
|
metrics?.gossipBlock.processBlockErrors.inc({ error: e instanceof BlockError ? e.type.code : "NOT_BLOCK_ERROR" });
|
|
512
|
-
logger[logLevel]("Error processing block", { slot,
|
|
512
|
+
logger[logLevel]("Error processing block", { slot, root: blockInput.blockRootHex, peer: peerIdStr }, e);
|
|
513
513
|
// TODO(fulu): Revisit when we prune block inputs
|
|
514
514
|
chain.seenBlockInputCache.prune(blockInput.blockRootHex);
|
|
515
515
|
});
|
|
@@ -520,8 +520,16 @@ function getSequentialHandlers(modules, options) {
|
|
|
520
520
|
const signedBlock = sszDeserialize(topic, serializedData);
|
|
521
521
|
try {
|
|
522
522
|
const blockInput = await validateBeaconBlock(signedBlock, topic.boundary.fork, peerIdStr, seenTimestampSec);
|
|
523
|
-
|
|
524
|
-
|
|
523
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
524
|
+
callInNextEventLoop(() => {
|
|
525
|
+
try {
|
|
526
|
+
chain.serializedCache.set(signedBlock, serializedData);
|
|
527
|
+
handleValidBeaconBlock(blockInput, peerIdStr, seenTimestampSec);
|
|
528
|
+
}
|
|
529
|
+
catch (e) {
|
|
530
|
+
logger.debug("Error handling gossip block", { slot: signedBlock.message.slot, root: blockInput.blockRootHex }, e);
|
|
531
|
+
}
|
|
532
|
+
});
|
|
525
533
|
}
|
|
526
534
|
catch (e) {
|
|
527
535
|
// Spec: IGNORE the block, ie not to re-publish to peers
|
|
@@ -534,6 +542,8 @@ function getSequentialHandlers(modules, options) {
|
|
|
534
542
|
// blockInput was optimistically seeded in validateBeaconBlock and retained on IGNORE
|
|
535
543
|
const blockInput = chain.seenBlockInputCache.get(e.type.root);
|
|
536
544
|
if (blockInput) {
|
|
545
|
+
// We're returning IGNORE (thrown below), so this block is not forwarded to peers. Unlike the
|
|
546
|
+
// happy path there is no rush to forward, so we don't need to wrap in callInNextEventLoop.
|
|
537
547
|
chain.serializedCache.set(signedBlock, serializedData);
|
|
538
548
|
// this is technically not a valid gossip block but gossip validation is a cheap subset of checks
|
|
539
549
|
// this runs the full state transition, so importing an equivocating-but-valid block here is safe.
|
|
@@ -553,26 +563,34 @@ function getSequentialHandlers(modules, options) {
|
|
|
553
563
|
throw new GossipActionError(GossipAction.REJECT, { code: "PRE_DENEB_BLOCK" });
|
|
554
564
|
}
|
|
555
565
|
const blockInput = await validateBeaconBlob(blobSidecar, topic.subnet, peerIdStr, seenTimestampSec);
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
566
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
567
|
+
callInNextEventLoop(() => {
|
|
568
|
+
try {
|
|
569
|
+
chain.serializedCache.set(blobSidecar, serializedData);
|
|
570
|
+
if (!blockInput.hasBlockAndAllData()) {
|
|
571
|
+
const cutoffTimeMs = getCutoffTimeMs(chain, blobSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
|
|
572
|
+
chain.logger.debug("Received gossip blob, waiting for full data availability", {
|
|
573
|
+
msToWait: cutoffTimeMs,
|
|
574
|
+
blobIndex: index,
|
|
575
|
+
...blockInput.getLogMeta(),
|
|
576
|
+
});
|
|
577
|
+
blockInput.waitForAllData(cutoffTimeMs).catch((_e) => {
|
|
578
|
+
chain.logger.debug("Waited for data after receiving gossip blob. Cut-off reached so attempting to fetch remainder of BlockInput", {
|
|
579
|
+
blobIndex: index,
|
|
580
|
+
...blockInput.getLogMeta(),
|
|
581
|
+
});
|
|
582
|
+
chain.emitter.emit(ChainEvent.incompleteBlockInput, {
|
|
583
|
+
blockInput,
|
|
584
|
+
peer: peerIdStr,
|
|
585
|
+
source: BlockInputSource.gossip,
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
catch (e) {
|
|
591
|
+
logger.debug("Error handling gossip blob", { slot: blobSlot, root: blockInput.blockRootHex, index }, e);
|
|
592
|
+
}
|
|
593
|
+
});
|
|
576
594
|
},
|
|
577
595
|
[GossipType.data_column_sidecar]: async ({ gossipData, topic, peerIdStr, seenTimestampSec, }) => {
|
|
578
596
|
const { fork } = topic.boundary;
|
|
@@ -592,50 +610,58 @@ function getSequentialHandlers(modules, options) {
|
|
|
592
610
|
}
|
|
593
611
|
// After gloas, data columns are tracked in PayloadEnvelopeInput
|
|
594
612
|
const payloadInput = await validatePayloadDataColumn(dataColumnSidecar, topic.subnet, peerIdStr, seenTimestampSec);
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
613
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
614
|
+
callInNextEventLoop(() => {
|
|
615
|
+
try {
|
|
616
|
+
chain.serializedCache.set(dataColumnSidecar, serializedData);
|
|
617
|
+
const payloadInputMeta = payloadInput.getLogMeta();
|
|
618
|
+
const { receivedColumns } = payloadInputMeta;
|
|
619
|
+
// it's not helpful to track every single column received
|
|
620
|
+
// instead of that, track 1st, 8th, 16th 32th, 64th, and 128th column
|
|
621
|
+
switch (receivedColumns) {
|
|
622
|
+
case 1:
|
|
623
|
+
case config.SAMPLES_PER_SLOT:
|
|
624
|
+
case 2 * config.SAMPLES_PER_SLOT:
|
|
625
|
+
case NUMBER_OF_COLUMNS / 4:
|
|
626
|
+
case NUMBER_OF_COLUMNS / 2:
|
|
627
|
+
case NUMBER_OF_COLUMNS:
|
|
628
|
+
metrics?.dataColumns.elapsedTimeTillReceived.observe({ receivedOrder: receivedColumns }, delaySec);
|
|
629
|
+
break;
|
|
630
|
+
}
|
|
631
|
+
if (!payloadInput.hasComputedAllData()) {
|
|
632
|
+
// if we've received at least half of the columns, trigger reconstruction of the rest
|
|
633
|
+
if (receivedColumns >= NUMBER_OF_COLUMNS / 2) {
|
|
634
|
+
chain.columnReconstructionTracker.triggerColumnReconstruction(payloadInput);
|
|
635
|
+
}
|
|
636
|
+
chain.logger.debug("Received gossip data column, payload envelope input not yet complete", {
|
|
637
|
+
dataColumnIndex: index,
|
|
638
|
+
...payloadInputMeta,
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
// NOTE: we do NOT call chain.processExecutionPayload here. That is triggered only by
|
|
642
|
+
// envelope arrival (gossip or API). An in-flight importExecutionPayload is awaiting
|
|
643
|
+
// payloadInput.waitForAllData(); addColumn above will resolve it once hasAllData flips.
|
|
644
|
+
if (!payloadInput.isComplete()) {
|
|
645
|
+
const cutoffTimeMs = getCutoffTimeMs(chain, dataColumnSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
|
|
646
|
+
// do not await here to not delay gossip validation
|
|
647
|
+
payloadInput.waitForEnvelopeAndAllData(cutoffTimeMs).catch((_e) => {
|
|
648
|
+
chain.logger.debug("Waited for envelope and data after receiving gossip column. Cut-off reached so emitting incompletePayloadEnvelope", {
|
|
649
|
+
dataColumnIndex: index,
|
|
650
|
+
...payloadInputMeta,
|
|
651
|
+
});
|
|
652
|
+
// TODO GLOAS: UnknownBlockSync to handle this event
|
|
653
|
+
chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
|
|
654
|
+
payloadInput,
|
|
655
|
+
peer: peerIdStr,
|
|
656
|
+
source: BlockInputSource.gossip,
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
}
|
|
614
660
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}
|
|
620
|
-
// NOTE: we do NOT call chain.processExecutionPayload here. That is triggered only by
|
|
621
|
-
// envelope arrival (gossip or API). An in-flight importExecutionPayload is awaiting
|
|
622
|
-
// payloadInput.waitForAllData(); addColumn above will resolve it once hasAllData flips.
|
|
623
|
-
if (!payloadInput.isComplete()) {
|
|
624
|
-
const cutoffTimeMs = getCutoffTimeMs(chain, dataColumnSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
|
|
625
|
-
// do not await here to not delay gossip validation
|
|
626
|
-
payloadInput.waitForEnvelopeAndAllData(cutoffTimeMs).catch((_e) => {
|
|
627
|
-
chain.logger.debug("Waited for envelope and data after receiving gossip column. Cut-off reached so emitting incompletePayloadEnvelope", {
|
|
628
|
-
dataColumnIndex: index,
|
|
629
|
-
...payloadInputMeta,
|
|
630
|
-
});
|
|
631
|
-
// TODO GLOAS: UnknownBlockSync to handle this event
|
|
632
|
-
chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
|
|
633
|
-
payloadInput,
|
|
634
|
-
peer: peerIdStr,
|
|
635
|
-
source: BlockInputSource.gossip,
|
|
636
|
-
});
|
|
637
|
-
});
|
|
638
|
-
}
|
|
661
|
+
catch (e) {
|
|
662
|
+
logger.debug("Error handling gossip data column", { slot: dataColumnSlot, root: payloadInput.blockRootHex, index }, e);
|
|
663
|
+
}
|
|
664
|
+
});
|
|
639
665
|
}
|
|
640
666
|
else {
|
|
641
667
|
if (config.getForkSeq(dataColumnSlot) < ForkSeq.fulu) {
|
|
@@ -651,49 +677,57 @@ function getSequentialHandlers(modules, options) {
|
|
|
651
677
|
}
|
|
652
678
|
// Before gloas, data columns are tracked in BlockInput
|
|
653
679
|
const blockInput = await validateBeaconDataColumn(dataColumnSidecar, serializedData, topic.subnet, peerIdStr, seenTimestampSec);
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
680
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
681
|
+
callInNextEventLoop(() => {
|
|
682
|
+
try {
|
|
683
|
+
chain.serializedCache.set(dataColumnSidecar, serializedData);
|
|
684
|
+
const blockInputMeta = blockInput.getLogMeta();
|
|
685
|
+
const { receivedColumns } = blockInputMeta;
|
|
686
|
+
// it's not helpful to track every single column received
|
|
687
|
+
// instead of that, track 1st, 8th, 16th 32th, 64th, and 128th column
|
|
688
|
+
switch (receivedColumns) {
|
|
689
|
+
case 1:
|
|
690
|
+
case config.SAMPLES_PER_SLOT:
|
|
691
|
+
case 2 * config.SAMPLES_PER_SLOT:
|
|
692
|
+
case NUMBER_OF_COLUMNS / 4:
|
|
693
|
+
case NUMBER_OF_COLUMNS / 2:
|
|
694
|
+
case NUMBER_OF_COLUMNS:
|
|
695
|
+
metrics?.dataColumns.elapsedTimeTillReceived.observe({ receivedOrder: receivedColumns }, delaySec);
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
if (!blockInput.hasComputedAllData()) {
|
|
699
|
+
// immediately attempt fetch of data columns from execution engine
|
|
700
|
+
chain.getBlobsTracker.triggerGetBlobs(blockInput);
|
|
701
|
+
// if we've received at least half of the columns, trigger reconstruction of the rest
|
|
702
|
+
if (blockInput.columnCount >= NUMBER_OF_COLUMNS / 2) {
|
|
703
|
+
chain.columnReconstructionTracker.triggerColumnReconstruction(blockInput);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
if (!blockInput.hasBlockAndAllData()) {
|
|
707
|
+
const cutoffTimeMs = getCutoffTimeMs(chain, dataColumnSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
|
|
708
|
+
chain.logger.debug("Received gossip data column, waiting for full data availability", {
|
|
709
|
+
msToWait: cutoffTimeMs,
|
|
710
|
+
dataColumnIndex: index,
|
|
711
|
+
...blockInputMeta,
|
|
712
|
+
});
|
|
713
|
+
// do not await here to not delay gossip validation
|
|
714
|
+
blockInput.waitForBlockAndAllData(cutoffTimeMs).catch((_e) => {
|
|
715
|
+
chain.logger.debug("Waited for data after receiving gossip column. Cut-off reached so attempting to fetch remainder of BlockInput", {
|
|
716
|
+
dataColumnIndex: index,
|
|
717
|
+
...blockInputMeta,
|
|
718
|
+
});
|
|
719
|
+
chain.emitter.emit(ChainEvent.incompleteBlockInput, {
|
|
720
|
+
blockInput,
|
|
721
|
+
peer: peerIdStr,
|
|
722
|
+
source: BlockInputSource.gossip,
|
|
723
|
+
});
|
|
724
|
+
});
|
|
725
|
+
}
|
|
675
726
|
}
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
msToWait: cutoffTimeMs,
|
|
681
|
-
dataColumnIndex: index,
|
|
682
|
-
...blockInputMeta,
|
|
683
|
-
});
|
|
684
|
-
// do not await here to not delay gossip validation
|
|
685
|
-
blockInput.waitForBlockAndAllData(cutoffTimeMs).catch((_e) => {
|
|
686
|
-
chain.logger.debug("Waited for data after receiving gossip column. Cut-off reached so attempting to fetch remainder of BlockInput", {
|
|
687
|
-
dataColumnIndex: index,
|
|
688
|
-
...blockInputMeta,
|
|
689
|
-
});
|
|
690
|
-
chain.emitter.emit(ChainEvent.incompleteBlockInput, {
|
|
691
|
-
blockInput,
|
|
692
|
-
peer: peerIdStr,
|
|
693
|
-
source: BlockInputSource.gossip,
|
|
694
|
-
});
|
|
695
|
-
});
|
|
696
|
-
}
|
|
727
|
+
catch (e) {
|
|
728
|
+
logger.debug("Error handling gossip data column", { slot: dataColumnSlot, root: blockInput.blockRootHex, index }, e);
|
|
729
|
+
}
|
|
730
|
+
});
|
|
697
731
|
}
|
|
698
732
|
},
|
|
699
733
|
[GossipType.beacon_aggregate_and_proof]: async ({ gossipData, topic, seenTimestampSec, }) => {
|
|
@@ -710,62 +744,76 @@ function getSequentialHandlers(modules, options) {
|
|
|
710
744
|
}
|
|
711
745
|
throw e;
|
|
712
746
|
}
|
|
713
|
-
// Handler
|
|
747
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
714
748
|
const { indexedAttestation, committeeValidatorIndices, attDataRootHex } = validationResult;
|
|
715
|
-
|
|
716
|
-
const aggregatedAttestation = signedAggregateAndProof.message.aggregate;
|
|
717
|
-
const insertOutcome = chain.aggregatedAttestationPool.add(aggregatedAttestation, attDataRootHex, indexedAttestation.attestingIndices.length, committeeValidatorIndices);
|
|
718
|
-
metrics?.opPool.aggregatedAttestationPool.gossipInsertOutcome.inc({ insertOutcome });
|
|
719
|
-
if (!options.dontSendGossipAttestationsToForkchoice) {
|
|
749
|
+
callInNextEventLoop(() => {
|
|
720
750
|
try {
|
|
721
|
-
chain.
|
|
751
|
+
chain.validatorMonitor?.registerGossipAggregatedAttestation(seenTimestampSec, signedAggregateAndProof, indexedAttestation);
|
|
752
|
+
const aggregatedAttestation = signedAggregateAndProof.message.aggregate;
|
|
753
|
+
const insertOutcome = chain.aggregatedAttestationPool.add(aggregatedAttestation, attDataRootHex, indexedAttestation.attestingIndices.length, committeeValidatorIndices);
|
|
754
|
+
metrics?.opPool.aggregatedAttestationPool.gossipInsertOutcome.inc({ insertOutcome });
|
|
755
|
+
if (!options.dontSendGossipAttestationsToForkchoice) {
|
|
756
|
+
chain.forkChoice.onAttestation(indexedAttestation, attDataRootHex);
|
|
757
|
+
}
|
|
758
|
+
chain.emitter.emit(routes.events.EventType.attestation, signedAggregateAndProof.message.aggregate);
|
|
722
759
|
}
|
|
723
760
|
catch (e) {
|
|
724
|
-
logger.debug("Error
|
|
761
|
+
logger.debug("Error handling gossip aggregate and proof", {
|
|
762
|
+
slot: signedAggregateAndProof.message.aggregate.data.slot,
|
|
763
|
+
root: toRootHex(signedAggregateAndProof.message.aggregate.data.beaconBlockRoot),
|
|
764
|
+
}, e);
|
|
725
765
|
}
|
|
726
|
-
}
|
|
727
|
-
chain.emitter.emit(routes.events.EventType.attestation, signedAggregateAndProof.message.aggregate);
|
|
766
|
+
});
|
|
728
767
|
},
|
|
729
768
|
[GossipType.attester_slashing]: async ({ gossipData, topic, }) => {
|
|
730
769
|
const { serializedData } = gossipData;
|
|
731
770
|
const { fork } = topic.boundary;
|
|
732
771
|
const attesterSlashing = sszDeserialize(topic, serializedData);
|
|
733
772
|
await validateGossipAttesterSlashing(chain, attesterSlashing);
|
|
734
|
-
// Handler
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
773
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
774
|
+
callInNextEventLoop(() => {
|
|
775
|
+
try {
|
|
776
|
+
chain.opPool.insertAttesterSlashing(fork, attesterSlashing);
|
|
777
|
+
chain.forkChoice.onAttesterSlashing(attesterSlashing);
|
|
778
|
+
chain.emitter.emit(routes.events.EventType.attesterSlashing, attesterSlashing);
|
|
779
|
+
}
|
|
780
|
+
catch (e) {
|
|
781
|
+
logger.debug("Error handling gossip attester slashing", { slot: attesterSlashing.attestation1.data.slot }, e);
|
|
782
|
+
}
|
|
783
|
+
});
|
|
743
784
|
},
|
|
744
785
|
[GossipType.proposer_slashing]: async ({ gossipData, topic, }) => {
|
|
745
786
|
const { serializedData } = gossipData;
|
|
746
787
|
const proposerSlashing = sszDeserialize(topic, serializedData);
|
|
747
788
|
await validateGossipProposerSlashing(chain, proposerSlashing);
|
|
748
|
-
// Handler
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
789
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
790
|
+
callInNextEventLoop(() => {
|
|
791
|
+
try {
|
|
792
|
+
chain.opPool.insertProposerSlashing(proposerSlashing);
|
|
793
|
+
chain.emitter.emit(routes.events.EventType.proposerSlashing, proposerSlashing);
|
|
794
|
+
}
|
|
795
|
+
catch (e) {
|
|
796
|
+
logger.debug("Error handling gossip proposer slashing", {
|
|
797
|
+
slot: proposerSlashing.signedHeader1.message.slot,
|
|
798
|
+
proposerIndex: proposerSlashing.signedHeader1.message.proposerIndex,
|
|
799
|
+
}, e);
|
|
800
|
+
}
|
|
801
|
+
});
|
|
756
802
|
},
|
|
757
803
|
[GossipType.voluntary_exit]: async ({ gossipData, topic }) => {
|
|
758
804
|
const { serializedData } = gossipData;
|
|
759
805
|
const voluntaryExit = sszDeserialize(topic, serializedData);
|
|
760
806
|
await validateGossipVoluntaryExit(chain, voluntaryExit);
|
|
761
|
-
// Handler
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
807
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
808
|
+
callInNextEventLoop(() => {
|
|
809
|
+
try {
|
|
810
|
+
chain.opPool.insertVoluntaryExit(voluntaryExit);
|
|
811
|
+
chain.emitter.emit(routes.events.EventType.voluntaryExit, voluntaryExit);
|
|
812
|
+
}
|
|
813
|
+
catch (e) {
|
|
814
|
+
logger.debug("Error handling gossip voluntary exit", { epoch: voluntaryExit.message.epoch, validatorIndex: voluntaryExit.message.validatorIndex }, e);
|
|
815
|
+
}
|
|
816
|
+
});
|
|
769
817
|
},
|
|
770
818
|
[GossipType.sync_committee_contribution_and_proof]: async ({ gossipData, topic, }) => {
|
|
771
819
|
const { serializedData } = gossipData;
|
|
@@ -776,16 +824,21 @@ function getSequentialHandlers(modules, options) {
|
|
|
776
824
|
}
|
|
777
825
|
throw e;
|
|
778
826
|
});
|
|
779
|
-
// Handler
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
827
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
828
|
+
callInNextEventLoop(() => {
|
|
829
|
+
try {
|
|
830
|
+
chain.validatorMonitor?.registerGossipSyncContributionAndProof(contributionAndProof.message, syncCommitteeParticipantIndices);
|
|
831
|
+
const insertOutcome = chain.syncContributionAndProofPool.add(contributionAndProof.message, syncCommitteeParticipantIndices.length);
|
|
832
|
+
metrics?.opPool.syncContributionAndProofPool.gossipInsertOutcome.inc({ insertOutcome });
|
|
833
|
+
chain.emitter.emit(routes.events.EventType.contributionAndProof, contributionAndProof);
|
|
834
|
+
}
|
|
835
|
+
catch (e) {
|
|
836
|
+
logger.debug("Error handling gossip contribution and proof", {
|
|
837
|
+
slot: contributionAndProof.message.contribution.slot,
|
|
838
|
+
subcommitteeIndex: contributionAndProof.message.contribution.subcommitteeIndex,
|
|
839
|
+
}, e);
|
|
840
|
+
}
|
|
841
|
+
});
|
|
789
842
|
},
|
|
790
843
|
[GossipType.sync_committee]: async ({ gossipData, topic }) => {
|
|
791
844
|
const { serializedData } = gossipData;
|
|
@@ -801,16 +854,19 @@ function getSequentialHandlers(modules, options) {
|
|
|
801
854
|
}
|
|
802
855
|
throw e;
|
|
803
856
|
}
|
|
804
|
-
// Handler
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
857
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
858
|
+
// add for ALL positions this validator holds in the subcommittee
|
|
859
|
+
callInNextEventLoop(() => {
|
|
860
|
+
try {
|
|
861
|
+
for (const indexInSubcommittee of indicesInSubcommittee) {
|
|
862
|
+
const insertOutcome = chain.syncCommitteeMessagePool.add(subnet, syncCommittee, indexInSubcommittee);
|
|
863
|
+
metrics?.opPool.syncCommitteeMessagePoolInsertOutcome.inc({ insertOutcome });
|
|
864
|
+
}
|
|
809
865
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
}
|
|
866
|
+
catch (e) {
|
|
867
|
+
logger.debug("Error handling gossip sync committee", { slot: syncCommittee.slot, subnet, validatorIndex: syncCommittee.validatorIndex }, e);
|
|
868
|
+
}
|
|
869
|
+
});
|
|
814
870
|
},
|
|
815
871
|
[GossipType.light_client_finality_update]: async ({ gossipData, topic, }) => {
|
|
816
872
|
const { serializedData } = gossipData;
|
|
@@ -827,14 +883,16 @@ function getSequentialHandlers(modules, options) {
|
|
|
827
883
|
const { serializedData } = gossipData;
|
|
828
884
|
const blsToExecutionChange = sszDeserialize(topic, serializedData);
|
|
829
885
|
await validateGossipBlsToExecutionChange(chain, blsToExecutionChange);
|
|
830
|
-
// Handler
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
886
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
887
|
+
callInNextEventLoop(() => {
|
|
888
|
+
try {
|
|
889
|
+
chain.opPool.insertBlsToExecutionChange(blsToExecutionChange);
|
|
890
|
+
chain.emitter.emit(routes.events.EventType.blsToExecutionChange, blsToExecutionChange);
|
|
891
|
+
}
|
|
892
|
+
catch (e) {
|
|
893
|
+
logger.debug("Error handling gossip bls to execution change", { validatorIndex: blsToExecutionChange.message.validatorIndex }, e);
|
|
894
|
+
}
|
|
895
|
+
});
|
|
838
896
|
},
|
|
839
897
|
[GossipType.execution_payload]: async ({ gossipData, topic, peerIdStr, seenTimestampSec, }) => {
|
|
840
898
|
const { serializedData } = gossipData;
|
|
@@ -878,99 +936,137 @@ function getSequentialHandlers(modules, options) {
|
|
|
878
936
|
blockRoot: blockRootHex,
|
|
879
937
|
});
|
|
880
938
|
}
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
939
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
940
|
+
callInNextEventLoop(() => {
|
|
941
|
+
try {
|
|
942
|
+
chain.serializedCache.set(signedEnvelope, serializedData);
|
|
943
|
+
payloadInput.addPayloadEnvelope({
|
|
944
|
+
envelope: signedEnvelope,
|
|
945
|
+
source: PayloadEnvelopeInputSource.gossip,
|
|
946
|
+
seenTimestampSec,
|
|
947
|
+
peerIdStr,
|
|
948
|
+
});
|
|
949
|
+
chain.emitter.emit(routes.events.EventType.executionPayloadGossip, {
|
|
950
|
+
slot,
|
|
951
|
+
builderIndex: envelope.builderIndex,
|
|
952
|
+
blockHash: toRootHex(envelope.payload.blockHash),
|
|
953
|
+
blockRoot: blockRootHex,
|
|
954
|
+
});
|
|
955
|
+
chain.processExecutionPayload(payloadInput, { validSignature: true }).catch((e) => {
|
|
956
|
+
// Adjust verbosity based on error type
|
|
957
|
+
let logLevel;
|
|
958
|
+
if (e instanceof PayloadError) {
|
|
959
|
+
switch (e.type.code) {
|
|
960
|
+
// BLOCK_NOT_IN_FORK_CHOICE should not happen, validateGossipExecutionPayloadEnvelope above
|
|
961
|
+
// already verified the block is in fork choice
|
|
962
|
+
case PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE:
|
|
963
|
+
case PayloadErrorCode.MISS_BLOCK_STATE:
|
|
964
|
+
case PayloadErrorCode.EXECUTION_ENGINE_ERROR:
|
|
965
|
+
// Errors might indicate an issue with our node or the connected EL client
|
|
966
|
+
logLevel = LogLevel.error;
|
|
967
|
+
break;
|
|
968
|
+
// INVALID_SIGNATURE should not happen, signature is verified during gossip validation
|
|
969
|
+
case PayloadErrorCode.INVALID_SIGNATURE:
|
|
970
|
+
case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
|
|
971
|
+
case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
|
|
972
|
+
core.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadGossipPayload");
|
|
973
|
+
// Misbehaving peer, but could highlight an issue in another client
|
|
974
|
+
logLevel = LogLevel.warn;
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
else {
|
|
979
|
+
// Any unexpected error
|
|
905
980
|
logLevel = LogLevel.error;
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
// Misbehaving peer, but could highlight an issue in another client
|
|
913
|
-
logLevel = LogLevel.warn;
|
|
914
|
-
break;
|
|
915
|
-
}
|
|
981
|
+
}
|
|
982
|
+
metrics?.gossipExecutionPayloadEnvelope.processPayloadErrors.inc({
|
|
983
|
+
error: e instanceof PayloadError ? e.type.code : "NOT_PAYLOAD_ERROR",
|
|
984
|
+
});
|
|
985
|
+
chain.logger[logLevel]("Error processing execution payload from gossip", { slot, root: blockRootHex, peer: peerIdStr }, e);
|
|
986
|
+
});
|
|
916
987
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
logLevel = LogLevel.error;
|
|
988
|
+
catch (e) {
|
|
989
|
+
logger.debug("Error handling gossip execution payload", { slot, root: blockRootHex }, e);
|
|
920
990
|
}
|
|
921
|
-
metrics?.gossipExecutionPayloadEnvelope.processPayloadErrors.inc({
|
|
922
|
-
error: e instanceof PayloadError ? e.type.code : "NOT_PAYLOAD_ERROR",
|
|
923
|
-
});
|
|
924
|
-
chain.logger[logLevel]("Error processing execution payload from gossip", { slot, peer: peerIdStr, root: blockRootHex }, e);
|
|
925
991
|
});
|
|
926
992
|
},
|
|
927
993
|
[GossipType.payload_attestation_message]: async ({ gossipData, topic, seenTimestampSec, }) => {
|
|
928
994
|
const { serializedData } = gossipData;
|
|
929
995
|
const payloadAttestationMessage = sszDeserialize(topic, serializedData);
|
|
930
996
|
const validationResult = await validateGossipPayloadAttestationMessage(chain, payloadAttestationMessage);
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
997
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
998
|
+
callInNextEventLoop(() => {
|
|
999
|
+
try {
|
|
1000
|
+
const delaySec = chain.clock.secFromSlot(payloadAttestationMessage.data.slot, seenTimestampSec);
|
|
1001
|
+
metrics?.gossipPayloadAttestationMessage.elapsedTimeTillReceived.observe({ source: OpSource.gossip }, delaySec);
|
|
1002
|
+
const nextSlotProposer = chain.getHeadState().getBeaconProposer(payloadAttestationMessage.data.slot + 1);
|
|
1003
|
+
const isNextSlotProposer = chain.beaconProposerCache.get(nextSlotProposer) !== undefined;
|
|
1004
|
+
if (isNextSlotProposer) {
|
|
1005
|
+
try {
|
|
1006
|
+
const insertOutcome = chain.payloadAttestationPool.add(payloadAttestationMessage, validationResult.attDataRootHex, validationResult.validatorCommitteeIndices);
|
|
1007
|
+
metrics?.opPool.payloadAttestationPool.gossipInsertOutcome.inc({ insertOutcome });
|
|
1008
|
+
}
|
|
1009
|
+
catch (e) {
|
|
1010
|
+
logger.debug("Error adding to payloadAttestation pool", {}, e);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
chain.forkChoice.notifyPtcMessages(toRootHex(payloadAttestationMessage.data.beaconBlockRoot), payloadAttestationMessage.data.slot, validationResult.validatorCommitteeIndices, payloadAttestationMessage.data.payloadPresent, payloadAttestationMessage.data.blobDataAvailable);
|
|
1014
|
+
chain.emitter.emit(routes.events.EventType.payloadAttestationMessage, {
|
|
1015
|
+
version: config.getForkName(payloadAttestationMessage.data.slot),
|
|
1016
|
+
data: payloadAttestationMessage,
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
catch (e) {
|
|
1020
|
+
logger.debug("Error handling gossip payload attestation message", {
|
|
1021
|
+
slot: payloadAttestationMessage.data.slot,
|
|
1022
|
+
root: toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
|
|
1023
|
+
}, e);
|
|
1024
|
+
}
|
|
944
1025
|
});
|
|
945
1026
|
},
|
|
946
1027
|
[GossipType.execution_payload_bid]: async ({ gossipData, topic, seenTimestampSec, }) => {
|
|
947
1028
|
const { serializedData } = gossipData;
|
|
948
1029
|
const executionPayloadBid = sszDeserialize(topic, serializedData);
|
|
949
1030
|
const { proposerIndex } = await validateGossipExecutionPayloadBid(chain, executionPayloadBid);
|
|
950
|
-
//
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1031
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
1032
|
+
callInNextEventLoop(() => {
|
|
1033
|
+
try {
|
|
1034
|
+
// this could be negative, because it's most likely the bid of next slot comes at this clock slot
|
|
1035
|
+
const elapsedSec = chain.clock.secFromSlot(executionPayloadBid.message.slot, seenTimestampSec);
|
|
1036
|
+
metrics?.gossipExecutionPayloadBid.elapsedTimeTillReceived.observe({ source: OpSource.gossip }, elapsedSec);
|
|
1037
|
+
// Handle valid payload bid by storing in a bid pool
|
|
1038
|
+
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid, Math.floor(elapsedSec * 1000));
|
|
1039
|
+
metrics?.opPool.executionPayloadBidPool.gossipInsertOutcome.inc({ insertOutcome });
|
|
1040
|
+
chain.validatorMonitor?.registerExecutionPayloadBid(OpSource.gossip, proposerIndex, executionPayloadBid.message);
|
|
1041
|
+
chain.emitter.emit(routes.events.EventType.executionPayloadBid, {
|
|
1042
|
+
version: config.getForkName(executionPayloadBid.message.slot),
|
|
1043
|
+
data: executionPayloadBid,
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
catch (e) {
|
|
1047
|
+
logger.debug("Error handling gossip execution payload bid", {
|
|
1048
|
+
slot: executionPayloadBid.message.slot,
|
|
1049
|
+
root: toRootHex(executionPayloadBid.message.parentBlockRoot),
|
|
1050
|
+
proposerIndex,
|
|
1051
|
+
}, e);
|
|
1052
|
+
}
|
|
965
1053
|
});
|
|
966
1054
|
},
|
|
967
1055
|
[GossipType.proposer_preferences]: async ({ gossipData, topic, }) => {
|
|
968
1056
|
const { serializedData } = gossipData;
|
|
969
1057
|
const signedProposerPreferences = sszDeserialize(topic, serializedData);
|
|
970
1058
|
await validateGossipProposerPreferences(chain, signedProposerPreferences);
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1059
|
+
// Handler - deferred to next event loop so the validation result propagates first
|
|
1060
|
+
callInNextEventLoop(() => {
|
|
1061
|
+
try {
|
|
1062
|
+
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
1063
|
+
version: config.getForkName(signedProposerPreferences.message.proposalSlot),
|
|
1064
|
+
data: signedProposerPreferences,
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
catch (e) {
|
|
1068
|
+
logger.debug("Error handling gossip proposer preferences", { proposalSlot: signedProposerPreferences.message.proposalSlot }, e);
|
|
1069
|
+
}
|
|
974
1070
|
});
|
|
975
1071
|
},
|
|
976
1072
|
};
|
|
@@ -997,43 +1093,9 @@ function getBatchHandlers(modules, options) {
|
|
|
997
1093
|
subnet: param.topic.subnet,
|
|
998
1094
|
}));
|
|
999
1095
|
const { results: validationResults, batchableBls } = await validateGossipAttestationsSameAttData(fork, chain, validationParams);
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
continue;
|
|
1004
|
-
}
|
|
1005
|
-
// null means no error
|
|
1006
|
-
results.push(null);
|
|
1007
|
-
// Handler
|
|
1008
|
-
const { indexedAttestation, attDataRootHex, attestation, committeeIndex, validatorCommitteeIndex, committeeSize, } = validationResult.result;
|
|
1009
|
-
chain.validatorMonitor?.registerGossipUnaggregatedAttestation(gossipHandlerParams[i].seenTimestampSec, indexedAttestation);
|
|
1010
|
-
const { subnet } = validationResult.result;
|
|
1011
|
-
try {
|
|
1012
|
-
// Node may be subscribe to extra subnets (long-lived random subnets). For those, validate the messages
|
|
1013
|
-
// but don't add to attestation pool, to save CPU and RAM
|
|
1014
|
-
if (aggregatorTracker.shouldAggregate(subnet, indexedAttestation.data.slot)) {
|
|
1015
|
-
const insertOutcome = chain.attestationPool.add(committeeIndex, attestation, attDataRootHex, validatorCommitteeIndex, committeeSize);
|
|
1016
|
-
metrics?.opPool.attestationPool.gossipInsertOutcome.inc({ insertOutcome });
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
catch (e) {
|
|
1020
|
-
logger.error("Error adding unaggregated attestation to pool", { subnet }, e);
|
|
1021
|
-
}
|
|
1022
|
-
if (!options.dontSendGossipAttestationsToForkchoice) {
|
|
1023
|
-
try {
|
|
1024
|
-
chain.forkChoice.onAttestation(indexedAttestation, attDataRootHex);
|
|
1025
|
-
}
|
|
1026
|
-
catch (e) {
|
|
1027
|
-
logger.debug("Error adding gossip unaggregated attestation to forkchoice", { subnet }, e);
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
if (isForkPostElectra(fork)) {
|
|
1031
|
-
chain.emitter.emit(routes.events.EventType.singleAttestation, attestation);
|
|
1032
|
-
}
|
|
1033
|
-
else {
|
|
1034
|
-
chain.emitter.emit(routes.events.EventType.attestation, attestation);
|
|
1035
|
-
chain.emitter.emit(routes.events.EventType.singleAttestation, toElectraSingleAttestation(attestation, indexedAttestation.attestingIndices[0]));
|
|
1036
|
-
}
|
|
1096
|
+
// verdicts computed synchronously and returned immediately
|
|
1097
|
+
for (const validationResult of validationResults) {
|
|
1098
|
+
results.push(validationResult.err ? validationResult.err : null);
|
|
1037
1099
|
}
|
|
1038
1100
|
if (batchableBls) {
|
|
1039
1101
|
metrics?.gossipAttestation.attestationBatchHistogram.observe(attestationCount);
|
|
@@ -1041,6 +1103,47 @@ function getBatchHandlers(modules, options) {
|
|
|
1041
1103
|
else {
|
|
1042
1104
|
metrics?.gossipAttestation.attestationNonBatchCount.inc(attestationCount);
|
|
1043
1105
|
}
|
|
1106
|
+
// Handler - deferred to next event loop so the validation result propagates first.
|
|
1107
|
+
callInNextEventLoop(() => {
|
|
1108
|
+
for (const [i, validationResult] of validationResults.entries()) {
|
|
1109
|
+
if (validationResult.err)
|
|
1110
|
+
continue;
|
|
1111
|
+
const { indexedAttestation, attDataRootHex, attestation, committeeIndex, validatorCommitteeIndex, committeeSize, subnet, } = validationResult.result;
|
|
1112
|
+
try {
|
|
1113
|
+
chain.validatorMonitor?.registerGossipUnaggregatedAttestation(gossipHandlerParams[i].seenTimestampSec, indexedAttestation);
|
|
1114
|
+
try {
|
|
1115
|
+
// Node may be subscribe to extra subnets (long-lived random subnets). For those, validate the messages
|
|
1116
|
+
// but don't add to attestation pool, to save CPU and RAM
|
|
1117
|
+
if (aggregatorTracker.shouldAggregate(subnet, indexedAttestation.data.slot)) {
|
|
1118
|
+
const insertOutcome = chain.attestationPool.add(committeeIndex, attestation, attDataRootHex, validatorCommitteeIndex, committeeSize);
|
|
1119
|
+
metrics?.opPool.attestationPool.gossipInsertOutcome.inc({ insertOutcome });
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
catch (e) {
|
|
1123
|
+
logger.debug("Error adding gossip unaggregated attestation to pool", { subnet }, e);
|
|
1124
|
+
}
|
|
1125
|
+
// Separate boundary: a pool insertion error above must not skip the fork-choice vote
|
|
1126
|
+
if (!options.dontSendGossipAttestationsToForkchoice) {
|
|
1127
|
+
try {
|
|
1128
|
+
chain.forkChoice.onAttestation(indexedAttestation, attDataRootHex);
|
|
1129
|
+
}
|
|
1130
|
+
catch (e) {
|
|
1131
|
+
logger.debug("Error adding gossip unaggregated attestation to forkchoice", { subnet }, e);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
if (isForkPostElectra(fork)) {
|
|
1135
|
+
chain.emitter.emit(routes.events.EventType.singleAttestation, attestation);
|
|
1136
|
+
}
|
|
1137
|
+
else {
|
|
1138
|
+
chain.emitter.emit(routes.events.EventType.attestation, attestation);
|
|
1139
|
+
chain.emitter.emit(routes.events.EventType.singleAttestation, toElectraSingleAttestation(attestation, indexedAttestation.attestingIndices[0]));
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
catch (e) {
|
|
1143
|
+
logger.debug("Error handling gossip attestation", { slot: indexedAttestation.data.slot, subnet }, e);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1044
1147
|
return results;
|
|
1045
1148
|
},
|
|
1046
1149
|
};
|