@lodestar/beacon-node 1.40.0-dev.9defa5c09b → 1.40.0-dev.b87b37f4d0
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 +15 -9
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +24 -0
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/rest/base.d.ts.map +1 -1
- package/lib/api/rest/base.js +2 -2
- package/lib/api/rest/base.js.map +1 -1
- package/lib/chain/ColumnReconstructionTracker.d.ts +2 -0
- package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
- package/lib/chain/ColumnReconstructionTracker.js +7 -3
- package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js +2 -1
- package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.d.ts +28 -0
- package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.js +38 -3
- package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
- package/lib/chain/blocks/importBlock.js +1 -1
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +1 -1
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.d.ts +2 -2
- package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js +2 -2
- package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +1 -2
- package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writeBlockInputToDb.js +8 -0
- package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
- package/lib/chain/bls/multithread/index.d.ts +3 -1
- package/lib/chain/bls/multithread/index.d.ts.map +1 -1
- package/lib/chain/bls/multithread/index.js +5 -3
- package/lib/chain/bls/multithread/index.js.map +1 -1
- package/lib/chain/bls/multithread/jobItem.d.ts +2 -2
- package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
- package/lib/chain/bls/multithread/jobItem.js +2 -2
- package/lib/chain/bls/multithread/jobItem.js.map +1 -1
- package/lib/chain/bls/singleThread.d.ts +4 -2
- package/lib/chain/bls/singleThread.d.ts.map +1 -1
- package/lib/chain/bls/singleThread.js +4 -2
- package/lib/chain/bls/singleThread.js.map +1 -1
- package/lib/chain/bls/utils.d.ts +2 -2
- package/lib/chain/bls/utils.d.ts.map +1 -1
- package/lib/chain/bls/utils.js +9 -6
- package/lib/chain/bls/utils.js.map +1 -1
- package/lib/chain/chain.d.ts +1 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +19 -31
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +2 -2
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +1 -2
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/options.d.ts +0 -1
- 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/regen/interface.d.ts +1 -1
- package/lib/chain/regen/queued.d.ts +1 -1
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts +2 -0
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +4 -1
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenGossipBlockInput.js +3 -3
- package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
- package/lib/chain/serializeState.d.ts.map +1 -1
- package/lib/chain/serializeState.js +2 -1
- package/lib/chain/serializeState.js.map +1 -1
- package/lib/chain/stateCache/index.d.ts +0 -2
- package/lib/chain/stateCache/index.d.ts.map +1 -1
- package/lib/chain/stateCache/index.js +0 -2
- package/lib/chain/stateCache/index.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +2 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +3 -0
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/validation/aggregateAndProof.js +3 -4
- package/lib/chain/validation/aggregateAndProof.js.map +1 -1
- package/lib/chain/validation/attestation.d.ts +2 -2
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +4 -4
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
- package/lib/chain/validation/attesterSlashing.js +1 -1
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
- package/lib/chain/validation/blobSidecar.js +4 -4
- package/lib/chain/validation/blobSidecar.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +2 -3
- 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 +4 -4
- package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +4 -3
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/proposerSlashing.js +1 -1
- package/lib/chain/validation/proposerSlashing.js.map +1 -1
- package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts +2 -3
- package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/aggregateAndProof.js +8 -3
- package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
- package/lib/chain/validation/signatureSets/contributionAndProof.d.ts +2 -2
- package/lib/chain/validation/signatureSets/contributionAndProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/contributionAndProof.js +3 -3
- package/lib/chain/validation/signatureSets/contributionAndProof.js.map +1 -1
- package/lib/chain/validation/signatureSets/selectionProof.d.ts +2 -3
- package/lib/chain/validation/signatureSets/selectionProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/selectionProof.js +8 -3
- package/lib/chain/validation/signatureSets/selectionProof.js.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommittee.d.ts +2 -2
- package/lib/chain/validation/signatureSets/syncCommittee.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommittee.js +3 -3
- package/lib/chain/validation/signatureSets/syncCommittee.js.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts +1 -2
- package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeContribution.js +2 -2
- package/lib/chain/validation/signatureSets/syncCommitteeContribution.js.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts +2 -2
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js +3 -3
- package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js.map +1 -1
- package/lib/chain/validation/syncCommittee.js +1 -1
- package/lib/chain/validation/syncCommittee.js.map +1 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.d.ts.map +1 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.js +3 -5
- package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +1 -1
- package/lib/chain/validation/voluntaryExit.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +7 -4
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/network/core/networkCore.d.ts +3 -0
- package/lib/network/core/networkCore.d.ts.map +1 -1
- package/lib/network/core/networkCore.js +9 -0
- package/lib/network/core/networkCore.js.map +1 -1
- package/lib/network/core/networkCoreWorker.js +3 -0
- package/lib/network/core/networkCoreWorker.js.map +1 -1
- package/lib/network/core/networkCoreWorkerHandler.d.ts +3 -0
- package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
- package/lib/network/core/networkCoreWorkerHandler.js +9 -0
- package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
- package/lib/network/core/types.d.ts +3 -0
- package/lib/network/core/types.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts +34 -0
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +123 -0
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/network.d.ts +3 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +9 -0
- package/lib/network/network.js.map +1 -1
- package/lib/network/options.d.ts +6 -0
- package/lib/network/options.d.ts.map +1 -1
- package/lib/network/options.js.map +1 -1
- package/lib/network/peers/peerManager.d.ts.map +1 -1
- package/lib/network/peers/peerManager.js +9 -0
- package/lib/network/peers/peerManager.js.map +1 -1
- package/lib/network/processor/gossipHandlers.js +1 -1
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/sync/backfill/backfill.d.ts.map +1 -1
- package/lib/sync/backfill/backfill.js +3 -4
- package/lib/sync/backfill/backfill.js.map +1 -1
- package/lib/sync/backfill/verify.d.ts +1 -2
- package/lib/sync/backfill/verify.d.ts.map +1 -1
- package/lib/sync/backfill/verify.js +2 -2
- package/lib/sync/backfill/verify.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +2 -2
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +1 -2
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/package.json +16 -16
- package/src/api/impl/beacon/blocks/index.ts +31 -19
- package/src/api/impl/lodestar/index.ts +29 -0
- package/src/api/impl/validator/index.ts +2 -1
- package/src/api/rest/base.ts +4 -4
- package/src/chain/ColumnReconstructionTracker.ts +8 -4
- package/src/chain/archiveStore/historicalState/getHistoricalState.ts +2 -1
- package/src/chain/blocks/blockInput/blockInput.ts +47 -4
- package/src/chain/blocks/importBlock.ts +1 -1
- package/src/chain/blocks/verifyBlock.ts +0 -1
- package/src/chain/blocks/verifyBlocksSignatures.ts +4 -12
- package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +1 -2
- package/src/chain/blocks/writeBlockInputToDb.ts +9 -0
- package/src/chain/bls/multithread/index.ts +7 -4
- package/src/chain/bls/multithread/jobItem.ts +7 -3
- package/src/chain/bls/singleThread.ts +5 -3
- package/src/chain/bls/utils.ts +15 -7
- package/src/chain/chain.ts +24 -35
- package/src/chain/initState.ts +2 -2
- package/src/chain/lightClient/index.ts +1 -2
- package/src/chain/options.ts +0 -2
- package/src/chain/regen/interface.ts +1 -1
- package/src/chain/regen/queued.ts +1 -2
- package/src/chain/regen/regen.ts +6 -1
- package/src/chain/seenCache/seenGossipBlockInput.ts +3 -3
- package/src/chain/serializeState.ts +2 -1
- package/src/chain/stateCache/index.ts +0 -2
- package/src/chain/stateCache/persistentCheckpointsCache.ts +6 -2
- package/src/chain/validation/aggregateAndProof.ts +3 -4
- package/src/chain/validation/attestation.ts +9 -13
- package/src/chain/validation/attesterSlashing.ts +1 -6
- package/src/chain/validation/blobSidecar.ts +3 -8
- package/src/chain/validation/block.ts +2 -3
- package/src/chain/validation/dataColumnSidecar.ts +3 -8
- package/src/chain/validation/executionPayloadBid.ts +5 -4
- package/src/chain/validation/payloadAttestationMessage.ts +1 -1
- package/src/chain/validation/proposerSlashing.ts +1 -6
- package/src/chain/validation/signatureSets/aggregateAndProof.ts +9 -14
- package/src/chain/validation/signatureSets/contributionAndProof.ts +2 -4
- package/src/chain/validation/signatureSets/selectionProof.ts +9 -9
- package/src/chain/validation/signatureSets/syncCommittee.ts +2 -4
- package/src/chain/validation/signatureSets/syncCommitteeContribution.ts +2 -3
- package/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +2 -4
- package/src/chain/validation/syncCommittee.ts +1 -1
- package/src/chain/validation/syncCommitteeContributionAndProof.ts +3 -5
- package/src/chain/validation/voluntaryExit.ts +1 -1
- package/src/chain/validatorMonitor.ts +10 -5
- package/src/network/core/networkCore.ts +12 -0
- package/src/network/core/networkCoreWorker.ts +3 -0
- package/src/network/core/networkCoreWorkerHandler.ts +9 -0
- package/src/network/core/types.ts +6 -0
- package/src/network/gossip/gossipsub.ts +147 -1
- package/src/network/network.ts +12 -0
- package/src/network/options.ts +6 -0
- package/src/network/peers/peerManager.ts +11 -0
- package/src/network/processor/gossipHandlers.ts +1 -1
- package/src/sync/backfill/backfill.ts +3 -4
- package/src/sync/backfill/verify.ts +2 -3
- package/src/sync/utils/downloadByRange.ts +2 -2
- package/src/sync/utils/downloadByRoot.ts +1 -2
- package/lib/chain/stateCache/blockStateCacheImpl.d.ts +0 -54
- package/lib/chain/stateCache/blockStateCacheImpl.d.ts.map +0 -1
- package/lib/chain/stateCache/blockStateCacheImpl.js +0 -130
- package/lib/chain/stateCache/blockStateCacheImpl.js.map +0 -1
- package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts +0 -60
- package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts.map +0 -1
- package/lib/chain/stateCache/inMemoryCheckpointsCache.js +0 -156
- package/lib/chain/stateCache/inMemoryCheckpointsCache.js.map +0 -1
- package/lib/util/bytes.d.ts +0 -3
- package/lib/util/bytes.d.ts.map +0 -1
- package/lib/util/bytes.js +0 -11
- package/lib/util/bytes.js.map +0 -1
- package/src/chain/stateCache/blockStateCacheImpl.ts +0 -149
- package/src/chain/stateCache/inMemoryCheckpointsCache.ts +0 -192
- package/src/util/bytes.ts +0 -11
|
@@ -138,11 +138,10 @@ export async function validateGossipBlock(
|
|
|
138
138
|
// in forky condition, make sure to populate ShufflingCache with regened state
|
|
139
139
|
chain.shufflingCache.processState(blockState);
|
|
140
140
|
|
|
141
|
-
// Extra conditions for merge fork blocks
|
|
142
141
|
// [REJECT] The block's execution payload timestamp is correct with respect to the slot
|
|
143
142
|
// -- i.e. execution_payload.timestamp == compute_timestamp_at_slot(state, block.slot).
|
|
144
143
|
if (isForkPostBellatrix(fork) && !isForkPostGloas(fork)) {
|
|
145
|
-
if (!isExecutionBlockBodyType(block.body)) throw Error("Not
|
|
144
|
+
if (!isExecutionBlockBodyType(block.body)) throw Error("Not execution block body type");
|
|
146
145
|
const executionPayload = block.body.executionPayload;
|
|
147
146
|
if (isExecutionStateType(blockState) && isExecutionEnabled(blockState, block)) {
|
|
148
147
|
const expectedTimestamp = computeTimeAtSlot(config, blockSlot, chain.genesisTime);
|
|
@@ -158,7 +157,7 @@ export async function validateGossipBlock(
|
|
|
158
157
|
|
|
159
158
|
// [REJECT] The proposer signature, signed_beacon_block.signature, is valid with respect to the proposer_index pubkey.
|
|
160
159
|
if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blockSlot, blockRoot, signedBlock.signature)) {
|
|
161
|
-
const signatureSet = getBlockProposerSignatureSet(chain.config,
|
|
160
|
+
const signatureSet = getBlockProposerSignatureSet(chain.config, signedBlock);
|
|
162
161
|
// Don't batch so verification is not delayed
|
|
163
162
|
if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) {
|
|
164
163
|
throw new BlockGossipError(GossipAction.REJECT, {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
getBlockHeaderProposerSignatureSetByParentStateSlot,
|
|
12
12
|
} from "@lodestar/state-transition";
|
|
13
13
|
import {Root, Slot, SubnetID, fulu, ssz} from "@lodestar/types";
|
|
14
|
-
import {toRootHex, verifyMerkleBranch} from "@lodestar/utils";
|
|
14
|
+
import {byteArrayEquals, toRootHex, verifyMerkleBranch} from "@lodestar/utils";
|
|
15
15
|
import {Metrics} from "../../metrics/metrics.js";
|
|
16
16
|
import {kzg} from "../../util/kzg.js";
|
|
17
17
|
import {
|
|
@@ -136,7 +136,6 @@ export async function validateGossipDataColumnSidecar(
|
|
|
136
136
|
if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blockHeader.slot, blockRootHex, signature)) {
|
|
137
137
|
const signatureSet = getBlockHeaderProposerSignatureSetByParentStateSlot(
|
|
138
138
|
chain.config,
|
|
139
|
-
chain.index2pubkey,
|
|
140
139
|
blockState.slot,
|
|
141
140
|
dataColumnSidecar.signedBlockHeader
|
|
142
141
|
);
|
|
@@ -319,7 +318,7 @@ export async function validateBlockDataColumnSidecars(
|
|
|
319
318
|
const firstSidecarSignedBlockHeader = dataColumnSidecars[0].signedBlockHeader;
|
|
320
319
|
const firstSidecarBlockHeader = firstSidecarSignedBlockHeader.message;
|
|
321
320
|
const firstBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(firstSidecarBlockHeader);
|
|
322
|
-
if (
|
|
321
|
+
if (!byteArrayEquals(blockRoot, firstBlockRoot)) {
|
|
323
322
|
throw new DataColumnSidecarValidationError(
|
|
324
323
|
{
|
|
325
324
|
code: DataColumnSidecarErrorCode.INCORRECT_BLOCK,
|
|
@@ -337,11 +336,7 @@ export async function validateBlockDataColumnSidecars(
|
|
|
337
336
|
const slot = firstSidecarSignedBlockHeader.message.slot;
|
|
338
337
|
const signature = firstSidecarSignedBlockHeader.signature;
|
|
339
338
|
if (!chain.seenBlockInputCache.isVerifiedProposerSignature(slot, rootHex, signature)) {
|
|
340
|
-
const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(
|
|
341
|
-
chain.config,
|
|
342
|
-
chain.index2pubkey,
|
|
343
|
-
firstSidecarSignedBlockHeader
|
|
344
|
-
);
|
|
339
|
+
const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(chain.config, firstSidecarSignedBlockHeader);
|
|
345
340
|
|
|
346
341
|
if (
|
|
347
342
|
!(await chain.bls.verifySignatureSets([signatureSet], {
|
|
@@ -53,7 +53,8 @@ async function validateExecutionPayloadBid(
|
|
|
53
53
|
|
|
54
54
|
// [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
|
|
55
55
|
// `is_active_builder(state, bid.builder_index)` returns `True`.
|
|
56
|
-
|
|
56
|
+
const builder = state.builders.getReadonly(bid.builderIndex);
|
|
57
|
+
if (!isActiveBuilder(builder, state.finalizedCheckpoint.epoch)) {
|
|
57
58
|
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
58
59
|
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
59
60
|
builderIndex: bid.builderIndex,
|
|
@@ -102,7 +103,7 @@ async function validateExecutionPayloadBid(
|
|
|
102
103
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
103
104
|
code: ExecutionPayloadBidErrorCode.BID_TOO_HIGH,
|
|
104
105
|
bidValue: bid.value,
|
|
105
|
-
builderBalance:
|
|
106
|
+
builderBalance: builder.balance,
|
|
106
107
|
});
|
|
107
108
|
}
|
|
108
109
|
|
|
@@ -122,8 +123,8 @@ async function validateExecutionPayloadBid(
|
|
|
122
123
|
|
|
123
124
|
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
124
125
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
125
|
-
PublicKey.fromBytes(
|
|
126
|
-
getExecutionPayloadBidSigningRoot(chain.config, state
|
|
126
|
+
PublicKey.fromBytes(builder.pubkey),
|
|
127
|
+
getExecutionPayloadBidSigningRoot(chain.config, state.slot, bid),
|
|
127
128
|
signedExecutionPayloadBid.signature
|
|
128
129
|
);
|
|
129
130
|
|
|
@@ -89,7 +89,7 @@ async function validatePayloadAttestationMessage(
|
|
|
89
89
|
// [REJECT] `payload_attestation_message.signature` is valid with respect to the validator's public key.
|
|
90
90
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
91
91
|
chain.index2pubkey[validatorIndex],
|
|
92
|
-
getPayloadAttestationDataSigningRoot(state, data),
|
|
92
|
+
getPayloadAttestationDataSigningRoot(chain.config, state.slot, data),
|
|
93
93
|
payloadAttestationMessage.signature
|
|
94
94
|
);
|
|
95
95
|
|
|
@@ -45,12 +45,7 @@ async function validateProposerSlashing(
|
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const signatureSets = getProposerSlashingSignatureSets(
|
|
49
|
-
chain.config,
|
|
50
|
-
chain.index2pubkey,
|
|
51
|
-
state.slot,
|
|
52
|
-
proposerSlashing
|
|
53
|
-
);
|
|
48
|
+
const signatureSets = getProposerSlashingSignatureSets(chain.config, state.slot, proposerSlashing);
|
|
54
49
|
if (!(await chain.bls.verifySignatureSets(signatureSets, {batchable: true, priority: prioritizeBls}))) {
|
|
55
50
|
throw new ProposerSlashingError(GossipAction.REJECT, {
|
|
56
51
|
code: ProposerSlashingErrorCode.INVALID,
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import {PublicKey} from "@chainsafe/blst";
|
|
2
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
3
2
|
import {DOMAIN_AGGREGATE_AND_PROOF, ForkSeq} from "@lodestar/params";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
computeSigningRoot,
|
|
7
|
-
computeStartSlotAtEpoch,
|
|
8
|
-
createSingleSignatureSetFromComponents,
|
|
9
|
-
} from "@lodestar/state-transition";
|
|
10
|
-
import {Epoch, SignedAggregateAndProof, ssz} from "@lodestar/types";
|
|
3
|
+
import {ISignatureSet, SignatureSetType, computeSigningRoot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
4
|
+
import {Epoch, SignedAggregateAndProof, ValidatorIndex, ssz} from "@lodestar/types";
|
|
11
5
|
|
|
12
6
|
export function getAggregateAndProofSigningRoot(
|
|
13
7
|
config: BeaconConfig,
|
|
@@ -27,12 +21,13 @@ export function getAggregateAndProofSigningRoot(
|
|
|
27
21
|
export function getAggregateAndProofSignatureSet(
|
|
28
22
|
config: BeaconConfig,
|
|
29
23
|
epoch: Epoch,
|
|
30
|
-
|
|
24
|
+
aggregatorIndex: ValidatorIndex,
|
|
31
25
|
aggregateAndProof: SignedAggregateAndProof
|
|
32
26
|
): ISignatureSet {
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
aggregateAndProof
|
|
37
|
-
|
|
27
|
+
return {
|
|
28
|
+
type: SignatureSetType.indexed,
|
|
29
|
+
index: aggregatorIndex,
|
|
30
|
+
signingRoot: getAggregateAndProofSigningRoot(config, epoch, aggregateAndProof),
|
|
31
|
+
signature: aggregateAndProof.signature,
|
|
32
|
+
};
|
|
38
33
|
}
|
|
@@ -3,7 +3,6 @@ import {DOMAIN_CONTRIBUTION_AND_PROOF} from "@lodestar/params";
|
|
|
3
3
|
import {
|
|
4
4
|
CachedBeaconStateAllForks,
|
|
5
5
|
ISignatureSet,
|
|
6
|
-
Index2PubkeyCache,
|
|
7
6
|
SignatureSetType,
|
|
8
7
|
computeSigningRoot,
|
|
9
8
|
} from "@lodestar/state-transition";
|
|
@@ -11,7 +10,6 @@ import {altair, ssz} from "@lodestar/types";
|
|
|
11
10
|
|
|
12
11
|
export function getContributionAndProofSignatureSet(
|
|
13
12
|
config: BeaconConfig,
|
|
14
|
-
index2pubkey: Index2PubkeyCache,
|
|
15
13
|
state: CachedBeaconStateAllForks,
|
|
16
14
|
signedContributionAndProof: altair.SignedContributionAndProof
|
|
17
15
|
): ISignatureSet {
|
|
@@ -22,8 +20,8 @@ export function getContributionAndProofSignatureSet(
|
|
|
22
20
|
);
|
|
23
21
|
const signingData = signedContributionAndProof.message;
|
|
24
22
|
return {
|
|
25
|
-
type: SignatureSetType.
|
|
26
|
-
|
|
23
|
+
type: SignatureSetType.indexed,
|
|
24
|
+
index: signedContributionAndProof.message.aggregatorIndex,
|
|
27
25
|
signingRoot: computeSigningRoot(ssz.altair.ContributionAndProof, signingData, domain),
|
|
28
26
|
signature: signedContributionAndProof.signature,
|
|
29
27
|
};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {PublicKey} from "@chainsafe/blst";
|
|
2
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
3
2
|
import {DOMAIN_SELECTION_PROOF} from "@lodestar/params";
|
|
4
|
-
import {ISignatureSet,
|
|
5
|
-
import {Slot, phase0, ssz} from "@lodestar/types";
|
|
3
|
+
import {ISignatureSet, SignatureSetType, computeSigningRoot} from "@lodestar/state-transition";
|
|
4
|
+
import {Slot, ValidatorIndex, phase0, ssz} from "@lodestar/types";
|
|
6
5
|
|
|
7
6
|
export function getSelectionProofSigningRoot(config: BeaconConfig, slot: Slot): Uint8Array {
|
|
8
7
|
// previously, we call `const selectionProofDomain = config.getDomain(state.slot, DOMAIN_SELECTION_PROOF, slot)`
|
|
@@ -16,12 +15,13 @@ export function getSelectionProofSigningRoot(config: BeaconConfig, slot: Slot):
|
|
|
16
15
|
export function getSelectionProofSignatureSet(
|
|
17
16
|
config: BeaconConfig,
|
|
18
17
|
slot: Slot,
|
|
19
|
-
|
|
18
|
+
aggregatorIndex: ValidatorIndex,
|
|
20
19
|
aggregateAndProof: phase0.SignedAggregateAndProof
|
|
21
20
|
): ISignatureSet {
|
|
22
|
-
return
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
return {
|
|
22
|
+
type: SignatureSetType.indexed,
|
|
23
|
+
index: aggregatorIndex,
|
|
24
|
+
signingRoot: getSelectionProofSigningRoot(config, slot),
|
|
25
|
+
signature: aggregateAndProof.message.selectionProof,
|
|
26
|
+
};
|
|
27
27
|
}
|
|
@@ -3,7 +3,6 @@ import {DOMAIN_SYNC_COMMITTEE} from "@lodestar/params";
|
|
|
3
3
|
import {
|
|
4
4
|
CachedBeaconStateAllForks,
|
|
5
5
|
ISignatureSet,
|
|
6
|
-
Index2PubkeyCache,
|
|
7
6
|
SignatureSetType,
|
|
8
7
|
computeSigningRoot,
|
|
9
8
|
} from "@lodestar/state-transition";
|
|
@@ -11,15 +10,14 @@ import {altair, ssz} from "@lodestar/types";
|
|
|
11
10
|
|
|
12
11
|
export function getSyncCommitteeSignatureSet(
|
|
13
12
|
config: BeaconConfig,
|
|
14
|
-
index2pubkey: Index2PubkeyCache,
|
|
15
13
|
state: CachedBeaconStateAllForks,
|
|
16
14
|
syncCommittee: altair.SyncCommitteeMessage
|
|
17
15
|
): ISignatureSet {
|
|
18
16
|
const domain = config.getDomain(state.slot, DOMAIN_SYNC_COMMITTEE, syncCommittee.slot);
|
|
19
17
|
|
|
20
18
|
return {
|
|
21
|
-
type: SignatureSetType.
|
|
22
|
-
|
|
19
|
+
type: SignatureSetType.indexed,
|
|
20
|
+
index: syncCommittee.validatorIndex,
|
|
23
21
|
signingRoot: computeSigningRoot(ssz.Root, syncCommittee.beaconBlockRoot, domain),
|
|
24
22
|
signature: syncCommittee.signature,
|
|
25
23
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {PublicKey} from "@chainsafe/blst";
|
|
2
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
3
2
|
import {DOMAIN_SYNC_COMMITTEE} from "@lodestar/params";
|
|
4
3
|
import {CachedBeaconStateAltair, ISignatureSet, SignatureSetType, computeSigningRoot} from "@lodestar/state-transition";
|
|
@@ -8,12 +7,12 @@ export function getSyncCommitteeContributionSignatureSet(
|
|
|
8
7
|
config: BeaconConfig,
|
|
9
8
|
state: CachedBeaconStateAltair,
|
|
10
9
|
contribution: altair.SyncCommitteeContribution,
|
|
11
|
-
|
|
10
|
+
participantIndices: number[]
|
|
12
11
|
): ISignatureSet {
|
|
13
12
|
const domain = config.getDomain(state.slot, DOMAIN_SYNC_COMMITTEE, contribution.slot);
|
|
14
13
|
return {
|
|
15
14
|
type: SignatureSetType.aggregate,
|
|
16
|
-
|
|
15
|
+
indices: participantIndices,
|
|
17
16
|
signingRoot: computeSigningRoot(ssz.Root, contribution.beaconBlockRoot, domain),
|
|
18
17
|
signature: contribution.signature,
|
|
19
18
|
};
|
|
@@ -3,7 +3,6 @@ import {DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF} from "@lodestar/params";
|
|
|
3
3
|
import {
|
|
4
4
|
CachedBeaconStateAllForks,
|
|
5
5
|
ISignatureSet,
|
|
6
|
-
Index2PubkeyCache,
|
|
7
6
|
SignatureSetType,
|
|
8
7
|
computeSigningRoot,
|
|
9
8
|
} from "@lodestar/state-transition";
|
|
@@ -11,7 +10,6 @@ import {altair, ssz} from "@lodestar/types";
|
|
|
11
10
|
|
|
12
11
|
export function getSyncCommitteeSelectionProofSignatureSet(
|
|
13
12
|
config: BeaconConfig,
|
|
14
|
-
index2pubkey: Index2PubkeyCache,
|
|
15
13
|
state: CachedBeaconStateAllForks,
|
|
16
14
|
contributionAndProof: altair.ContributionAndProof
|
|
17
15
|
): ISignatureSet {
|
|
@@ -22,8 +20,8 @@ export function getSyncCommitteeSelectionProofSignatureSet(
|
|
|
22
20
|
subcommitteeIndex: contributionAndProof.contribution.subcommitteeIndex,
|
|
23
21
|
};
|
|
24
22
|
return {
|
|
25
|
-
type: SignatureSetType.
|
|
26
|
-
|
|
23
|
+
type: SignatureSetType.indexed,
|
|
24
|
+
index: contributionAndProof.aggregatorIndex,
|
|
27
25
|
signingRoot: computeSigningRoot(ssz.altair.SyncAggregatorSelectionData, signingData, domain),
|
|
28
26
|
signature: contributionAndProof.selectionProof,
|
|
29
27
|
};
|
|
@@ -89,7 +89,7 @@ async function validateSyncCommitteeSigOnly(
|
|
|
89
89
|
syncCommittee: altair.SyncCommitteeMessage,
|
|
90
90
|
prioritizeBls = false
|
|
91
91
|
): Promise<void> {
|
|
92
|
-
const signatureSet = getSyncCommitteeSignatureSet(chain.config,
|
|
92
|
+
const signatureSet = getSyncCommitteeSignatureSet(chain.config, headState, syncCommittee);
|
|
93
93
|
if (!(await chain.bls.verifySignatureSets([signatureSet], {batchable: true, priority: prioritizeBls}))) {
|
|
94
94
|
throw new SyncCommitteeError(GossipAction.REJECT, {
|
|
95
95
|
code: SyncCommitteeErrorCode.INVALID_SIGNATURE,
|
|
@@ -21,7 +21,6 @@ export async function validateSyncCommitteeGossipContributionAndProof(
|
|
|
21
21
|
const contributionAndProof = signedContributionAndProof.message;
|
|
22
22
|
const {contribution, aggregatorIndex} = contributionAndProof;
|
|
23
23
|
const {subcommitteeIndex, slot} = contribution;
|
|
24
|
-
const {index2pubkey} = chain;
|
|
25
24
|
|
|
26
25
|
const headState = chain.getHeadState();
|
|
27
26
|
validateGossipSyncCommitteeExceptSig(chain, headState, subcommitteeIndex, {
|
|
@@ -74,14 +73,13 @@ export async function validateSyncCommitteeGossipContributionAndProof(
|
|
|
74
73
|
// i.e. state.validators[contribution_and_proof.aggregator_index].pubkey in get_sync_subcommittee_pubkeys(state, contribution.subcommittee_index).
|
|
75
74
|
// > Checked in validateGossipSyncCommitteeExceptSig()
|
|
76
75
|
|
|
77
|
-
const participantPubkeys = syncCommitteeParticipantIndices.map((validatorIndex) => index2pubkey[validatorIndex]);
|
|
78
76
|
const signatureSets = [
|
|
79
77
|
// [REJECT] The contribution_and_proof.selection_proof is a valid signature of the SyncAggregatorSelectionData
|
|
80
78
|
// derived from the contribution by the validator with index contribution_and_proof.aggregator_index.
|
|
81
|
-
getSyncCommitteeSelectionProofSignatureSet(chain.config,
|
|
79
|
+
getSyncCommitteeSelectionProofSignatureSet(chain.config, headState, contributionAndProof),
|
|
82
80
|
|
|
83
81
|
// [REJECT] The aggregator signature, signed_contribution_and_proof.signature, is valid.
|
|
84
|
-
getContributionAndProofSignatureSet(chain.config,
|
|
82
|
+
getContributionAndProofSignatureSet(chain.config, headState, signedContributionAndProof),
|
|
85
83
|
|
|
86
84
|
// [REJECT] The aggregate signature is valid for the message beacon_block_root and aggregate pubkey derived from
|
|
87
85
|
// the participation info in aggregation_bits for the subcommittee specified by the contribution.subcommittee_index.
|
|
@@ -89,7 +87,7 @@ export async function validateSyncCommitteeGossipContributionAndProof(
|
|
|
89
87
|
chain.config,
|
|
90
88
|
headState as CachedBeaconStateAltair,
|
|
91
89
|
contribution,
|
|
92
|
-
|
|
90
|
+
syncCommitteeParticipantIndices
|
|
93
91
|
),
|
|
94
92
|
];
|
|
95
93
|
|
|
@@ -59,7 +59,7 @@ async function validateVoluntaryExit(
|
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
const signatureSet = getVoluntaryExitSignatureSet(chain.config,
|
|
62
|
+
const signatureSet = getVoluntaryExitSignatureSet(chain.config, state.slot, voluntaryExit);
|
|
63
63
|
if (!(await chain.bls.verifySignatureSets([signatureSet], {batchable: true, priority: prioritizeBls}))) {
|
|
64
64
|
throw new VoluntaryExitError(GossipAction.REJECT, {
|
|
65
65
|
code: VoluntaryExitErrorCode.INVALID_SIGNATURE,
|
|
@@ -347,6 +347,9 @@ export function createValidatorMonitor(
|
|
|
347
347
|
return;
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
+
// Track total balance instead of per-validator balance to reduce metric cardinality
|
|
351
|
+
let totalBalance = 0;
|
|
352
|
+
|
|
350
353
|
for (const [index, monitoredValidator] of validators.entries()) {
|
|
351
354
|
// We subtract two from the state of the epoch that generated these summaries.
|
|
352
355
|
//
|
|
@@ -405,7 +408,7 @@ export function createValidatorMonitor(
|
|
|
405
408
|
|
|
406
409
|
const balance = balances?.[index];
|
|
407
410
|
if (balance !== undefined) {
|
|
408
|
-
|
|
411
|
+
totalBalance += balance;
|
|
409
412
|
}
|
|
410
413
|
|
|
411
414
|
if (!summary.isPrevSourceAttester || !summary.isPrevTargetAttester || !summary.isPrevHeadAttester) {
|
|
@@ -420,6 +423,10 @@ export function createValidatorMonitor(
|
|
|
420
423
|
});
|
|
421
424
|
}
|
|
422
425
|
}
|
|
426
|
+
|
|
427
|
+
if (balances !== undefined) {
|
|
428
|
+
validatorMonitorMetrics?.prevEpochOnChainBalance.set(totalBalance);
|
|
429
|
+
}
|
|
423
430
|
},
|
|
424
431
|
|
|
425
432
|
registerBeaconBlock(src, delaySec, block) {
|
|
@@ -1153,11 +1160,9 @@ function createValidatorMonitorMetrics(register: RegistryMetricCreator) {
|
|
|
1153
1160
|
}),
|
|
1154
1161
|
|
|
1155
1162
|
// Validator Monitor Metrics (per-epoch summaries)
|
|
1156
|
-
|
|
1157
|
-
prevEpochOnChainBalance: register.gauge<{index: number}>({
|
|
1163
|
+
prevEpochOnChainBalance: register.gauge({
|
|
1158
1164
|
name: "validator_monitor_prev_epoch_on_chain_balance",
|
|
1159
|
-
help: "
|
|
1160
|
-
labelNames: ["index"],
|
|
1165
|
+
help: "Total balance of all monitored validators after an epoch",
|
|
1161
1166
|
}),
|
|
1162
1167
|
prevEpochOnChainAttesterHit: register.gauge({
|
|
1163
1168
|
name: "validator_monitor_prev_epoch_on_chain_attester_hit_total",
|
|
@@ -454,6 +454,18 @@ export class NetworkCore implements INetworkCore {
|
|
|
454
454
|
await this.libp2p.hangUp(peerIdFromString(peerIdStr));
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
+
async addDirectPeer(peer: routes.lodestar.DirectPeer): Promise<string | null> {
|
|
458
|
+
return this.gossip.addDirectPeer(peer);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async removeDirectPeer(peerIdStr: PeerIdStr): Promise<boolean> {
|
|
462
|
+
return this.gossip.removeDirectPeer(peerIdStr);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
async getDirectPeers(): Promise<string[]> {
|
|
466
|
+
return this.gossip.getDirectPeers();
|
|
467
|
+
}
|
|
468
|
+
|
|
457
469
|
private _dumpPeer(peerIdStr: string, connections: Connection[]): routes.lodestar.LodestarNodePeer {
|
|
458
470
|
const peerData = this.peersData.connectedPeers.get(peerIdStr);
|
|
459
471
|
const fork = this.config.getForkName(this.clock.currentSlot);
|
|
@@ -153,6 +153,9 @@ const libp2pWorkerApi: NetworkWorkerApi = {
|
|
|
153
153
|
getConnectedPeerCount: () => core.getConnectedPeerCount(),
|
|
154
154
|
connectToPeer: (peer, multiaddr) => core.connectToPeer(peer, multiaddr),
|
|
155
155
|
disconnectPeer: (peer) => core.disconnectPeer(peer),
|
|
156
|
+
addDirectPeer: (peer) => core.addDirectPeer(peer),
|
|
157
|
+
removeDirectPeer: (peerId) => core.removeDirectPeer(peerId),
|
|
158
|
+
getDirectPeers: () => core.getDirectPeers(),
|
|
156
159
|
dumpPeers: () => core.dumpPeers(),
|
|
157
160
|
dumpPeer: (peerIdStr) => core.dumpPeer(peerIdStr),
|
|
158
161
|
dumpPeerScoreStats: () => core.dumpPeerScoreStats(),
|
|
@@ -247,6 +247,15 @@ export class WorkerNetworkCore implements INetworkCore {
|
|
|
247
247
|
disconnectPeer(peer: PeerIdStr): Promise<void> {
|
|
248
248
|
return this.getApi().disconnectPeer(peer);
|
|
249
249
|
}
|
|
250
|
+
addDirectPeer(peer: routes.lodestar.DirectPeer): Promise<string | null> {
|
|
251
|
+
return this.getApi().addDirectPeer(peer);
|
|
252
|
+
}
|
|
253
|
+
removeDirectPeer(peerId: PeerIdStr): Promise<boolean> {
|
|
254
|
+
return this.getApi().removeDirectPeer(peerId);
|
|
255
|
+
}
|
|
256
|
+
getDirectPeers(): Promise<string[]> {
|
|
257
|
+
return this.getApi().getDirectPeers();
|
|
258
|
+
}
|
|
250
259
|
dumpPeers(): Promise<routes.lodestar.LodestarNodePeer[]> {
|
|
251
260
|
return this.getApi().dumpPeers();
|
|
252
261
|
}
|
|
@@ -30,6 +30,12 @@ export interface INetworkCorePublic {
|
|
|
30
30
|
// Debug
|
|
31
31
|
connectToPeer(peer: PeerIdStr, multiaddr: MultiaddrStr[]): Promise<void>;
|
|
32
32
|
disconnectPeer(peer: PeerIdStr): Promise<void>;
|
|
33
|
+
|
|
34
|
+
// Direct peers management
|
|
35
|
+
addDirectPeer(peer: routes.lodestar.DirectPeer): Promise<string | null>;
|
|
36
|
+
removeDirectPeer(peerId: PeerIdStr): Promise<boolean>;
|
|
37
|
+
getDirectPeers(): Promise<string[]>;
|
|
38
|
+
|
|
33
39
|
dumpPeers(): Promise<routes.lodestar.LodestarNodePeer[]>;
|
|
34
40
|
dumpPeer(peerIdStr: PeerIdStr): Promise<routes.lodestar.LodestarNodePeer | undefined>;
|
|
35
41
|
dumpPeerScoreStats(): Promise<PeerScoreStats>;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import {peerIdFromString} from "@libp2p/peer-id";
|
|
2
|
+
import {multiaddr} from "@multiformats/multiaddr";
|
|
3
|
+
import {ENR} from "@chainsafe/enr";
|
|
1
4
|
import {GossipSub, GossipsubEvents} from "@chainsafe/libp2p-gossipsub";
|
|
2
5
|
import {MetricsRegister, TopicLabel, TopicStrToLabel} from "@chainsafe/libp2p-gossipsub/metrics";
|
|
3
6
|
import {PeerScoreParams} from "@chainsafe/libp2p-gossipsub/score";
|
|
4
|
-
import {SignaturePolicy, TopicStr} from "@chainsafe/libp2p-gossipsub/types";
|
|
7
|
+
import {AddrInfo, SignaturePolicy, TopicStr} from "@chainsafe/libp2p-gossipsub/types";
|
|
8
|
+
import {routes} from "@lodestar/api";
|
|
5
9
|
import {BeaconConfig, ForkBoundary} from "@lodestar/config";
|
|
6
10
|
import {ATTESTATION_SUBNET_COUNT, SLOTS_PER_EPOCH, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
|
|
7
11
|
import {SubnetID} from "@lodestar/types";
|
|
@@ -55,6 +59,12 @@ export type Eth2GossipsubOpts = {
|
|
|
55
59
|
disableFloodPublish?: boolean;
|
|
56
60
|
skipParamsLog?: boolean;
|
|
57
61
|
disableLightClientServer?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Direct peers for GossipSub - these peers maintain permanent mesh connections without GRAFT/PRUNE.
|
|
64
|
+
* Supports multiaddr strings with peer ID (e.g., "/ip4/192.168.1.1/tcp/9000/p2p/16Uiu2HAmKLhW7...")
|
|
65
|
+
* or ENR strings (e.g., "enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOo...")
|
|
66
|
+
*/
|
|
67
|
+
directPeers?: string[];
|
|
58
68
|
};
|
|
59
69
|
|
|
60
70
|
export type ForkBoundaryLabel = string;
|
|
@@ -78,6 +88,7 @@ export class Eth2Gossipsub extends GossipSub {
|
|
|
78
88
|
private readonly logger: Logger;
|
|
79
89
|
private readonly peersData: PeersData;
|
|
80
90
|
private readonly events: NetworkEventBus;
|
|
91
|
+
private readonly libp2p: Libp2p;
|
|
81
92
|
|
|
82
93
|
// Internal caches
|
|
83
94
|
private readonly gossipTopicCache: GossipTopicCache;
|
|
@@ -97,6 +108,9 @@ export class Eth2Gossipsub extends GossipSub {
|
|
|
97
108
|
);
|
|
98
109
|
}
|
|
99
110
|
|
|
111
|
+
// Parse direct peers from multiaddr strings to AddrInfo objects
|
|
112
|
+
const directPeers = parseDirectPeers(opts.directPeers ?? [], logger);
|
|
113
|
+
|
|
100
114
|
// Gossipsub parameters defined here:
|
|
101
115
|
// https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#the-gossip-domain-gossipsub
|
|
102
116
|
super(modules.libp2p.services.components, {
|
|
@@ -106,6 +120,7 @@ export class Eth2Gossipsub extends GossipSub {
|
|
|
106
120
|
Dlo: gossipsubDLow ?? GOSSIP_D_LOW,
|
|
107
121
|
Dhi: gossipsubDHigh ?? GOSSIP_D_HIGH,
|
|
108
122
|
Dlazy: 6,
|
|
123
|
+
directPeers,
|
|
109
124
|
heartbeatInterval: GOSSIPSUB_HEARTBEAT_INTERVAL,
|
|
110
125
|
fanoutTTL: 60 * 1000,
|
|
111
126
|
mcacheLength: 6,
|
|
@@ -146,6 +161,7 @@ export class Eth2Gossipsub extends GossipSub {
|
|
|
146
161
|
this.logger = logger;
|
|
147
162
|
this.peersData = peersData;
|
|
148
163
|
this.events = events;
|
|
164
|
+
this.libp2p = modules.libp2p;
|
|
149
165
|
this.gossipTopicCache = gossipTopicCache;
|
|
150
166
|
|
|
151
167
|
this.addEventListener("gossipsub:message", this.onGossipsubMessage.bind(this));
|
|
@@ -328,6 +344,64 @@ export class Eth2Gossipsub extends GossipSub {
|
|
|
328
344
|
this.reportMessageValidationResult(data.msgId, data.propagationSource, data.acceptance);
|
|
329
345
|
});
|
|
330
346
|
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Add a peer as a direct peer at runtime. Accepts multiaddr with peer ID or ENR string.
|
|
350
|
+
* Direct peers maintain permanent mesh connections without GRAFT/PRUNE negotiation.
|
|
351
|
+
*/
|
|
352
|
+
async addDirectPeer(peerStr: routes.lodestar.DirectPeer): Promise<string | null> {
|
|
353
|
+
const parsed = parseDirectPeers([peerStr], this.logger);
|
|
354
|
+
if (parsed.length === 0) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const {id: peerId, addrs} = parsed[0];
|
|
359
|
+
const peerIdStr = peerId.toString();
|
|
360
|
+
|
|
361
|
+
// Prevent adding self as a direct peer
|
|
362
|
+
if (peerId.equals(this.libp2p.peerId)) {
|
|
363
|
+
this.logger.warn("Cannot add self as a direct peer", {peerId: peerIdStr});
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Direct peers need addresses to connect - reject if none provided
|
|
368
|
+
if (addrs.length === 0) {
|
|
369
|
+
this.logger.warn("Cannot add direct peer without addresses", {peerId: peerIdStr});
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Add addresses to peer store first so we can connect
|
|
374
|
+
try {
|
|
375
|
+
await this.libp2p.peerStore.merge(peerId, {multiaddrs: addrs});
|
|
376
|
+
} catch (e) {
|
|
377
|
+
this.logger.warn("Failed to add direct peer addresses to peer store", {peerId: peerIdStr}, e as Error);
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Add to direct peers set only after addresses are stored
|
|
382
|
+
this.direct.add(peerIdStr);
|
|
383
|
+
|
|
384
|
+
this.logger.info("Added direct peer via API", {peerId: peerIdStr});
|
|
385
|
+
return peerIdStr;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Remove a peer from direct peers.
|
|
390
|
+
*/
|
|
391
|
+
removeDirectPeer(peerIdStr: string): boolean {
|
|
392
|
+
const removed = this.direct.delete(peerIdStr);
|
|
393
|
+
if (removed) {
|
|
394
|
+
this.logger.info("Removed direct peer via API", {peerId: peerIdStr});
|
|
395
|
+
}
|
|
396
|
+
return removed;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Get list of current direct peer IDs.
|
|
401
|
+
*/
|
|
402
|
+
getDirectPeers(): string[] {
|
|
403
|
+
return Array.from(this.direct);
|
|
404
|
+
}
|
|
331
405
|
}
|
|
332
406
|
|
|
333
407
|
/**
|
|
@@ -381,3 +455,75 @@ function getForkBoundaryLabel(boundary: ForkBoundary): ForkBoundaryLabel {
|
|
|
381
455
|
|
|
382
456
|
return label;
|
|
383
457
|
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Parse direct peer strings into AddrInfo objects for GossipSub.
|
|
461
|
+
* Direct peers maintain permanent mesh connections without GRAFT/PRUNE negotiation.
|
|
462
|
+
*
|
|
463
|
+
* Supported formats:
|
|
464
|
+
* - Multiaddr with peer ID: `/ip4/192.168.1.1/tcp/9000/p2p/16Uiu2HAmKLhW7...`
|
|
465
|
+
* - ENR: `enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOo...`
|
|
466
|
+
*
|
|
467
|
+
* For multiaddrs, the string must contain a /p2p/ component with the peer ID.
|
|
468
|
+
* For ENRs, the TCP multiaddr and peer ID are extracted from the encoded record.
|
|
469
|
+
*/
|
|
470
|
+
export function parseDirectPeers(directPeerStrs: routes.lodestar.DirectPeer[], logger: Logger): AddrInfo[] {
|
|
471
|
+
const directPeers: AddrInfo[] = [];
|
|
472
|
+
|
|
473
|
+
for (const peerStr of directPeerStrs) {
|
|
474
|
+
// Check if this is an ENR (starts with "enr:")
|
|
475
|
+
if (peerStr.startsWith("enr:")) {
|
|
476
|
+
try {
|
|
477
|
+
const enr = ENR.decodeTxt(peerStr);
|
|
478
|
+
const peerId = enr.peerId;
|
|
479
|
+
|
|
480
|
+
// Get TCP multiaddr from ENR
|
|
481
|
+
const multiaddrTCP = enr.getLocationMultiaddr("tcp");
|
|
482
|
+
if (!multiaddrTCP) {
|
|
483
|
+
logger.warn("ENR does not contain TCP multiaddr", {enr: peerStr});
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
directPeers.push({
|
|
488
|
+
id: peerId,
|
|
489
|
+
addrs: [multiaddrTCP],
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
logger.info("Added direct peer from ENR", {peerId: peerId.toString(), addr: multiaddrTCP.toString()});
|
|
493
|
+
} catch (e) {
|
|
494
|
+
logger.warn("Failed to parse direct peer ENR", {enr: peerStr}, e as Error);
|
|
495
|
+
}
|
|
496
|
+
} else {
|
|
497
|
+
// Parse as multiaddr
|
|
498
|
+
try {
|
|
499
|
+
const ma = multiaddr(peerStr);
|
|
500
|
+
|
|
501
|
+
const peerIdStr = ma.getPeerId();
|
|
502
|
+
if (!peerIdStr) {
|
|
503
|
+
logger.warn("Direct peer multiaddr must contain /p2p/ component with peer ID", {multiaddr: peerStr});
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
try {
|
|
508
|
+
const peerId = peerIdFromString(peerIdStr);
|
|
509
|
+
|
|
510
|
+
// Get the address without the /p2p/ component
|
|
511
|
+
const addr = ma.decapsulate("/p2p/" + peerIdStr);
|
|
512
|
+
|
|
513
|
+
directPeers.push({
|
|
514
|
+
id: peerId,
|
|
515
|
+
addrs: [addr],
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
logger.info("Added direct peer", {peerId: peerIdStr, addr: addr.toString()});
|
|
519
|
+
} catch (e) {
|
|
520
|
+
logger.warn("Invalid peer ID in direct peer multiaddr", {multiaddr: peerStr, peerId: peerIdStr}, e as Error);
|
|
521
|
+
}
|
|
522
|
+
} catch (e) {
|
|
523
|
+
logger.warn("Failed to parse direct peer multiaddr", {multiaddr: peerStr}, e as Error);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return directPeers;
|
|
529
|
+
}
|
package/src/network/network.ts
CHANGED
|
@@ -641,6 +641,18 @@ export class Network implements INetwork {
|
|
|
641
641
|
return this.core.disconnectPeer(peer);
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
+
addDirectPeer(peer: routes.lodestar.DirectPeer): Promise<string | null> {
|
|
645
|
+
return this.core.addDirectPeer(peer);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
removeDirectPeer(peerId: string): Promise<boolean> {
|
|
649
|
+
return this.core.removeDirectPeer(peerId);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
getDirectPeers(): Promise<string[]> {
|
|
653
|
+
return this.core.getDirectPeers();
|
|
654
|
+
}
|
|
655
|
+
|
|
644
656
|
dumpPeer(peerIdStr: string): Promise<routes.lodestar.LodestarNodePeer | undefined> {
|
|
645
657
|
return this.core.dumpPeer(peerIdStr);
|
|
646
658
|
}
|