@lodestar/beacon-node 1.45.0-dev.e10fb5e991 → 1.45.0-dev.e6d38ecb03
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/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +2 -42
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/index.js +46 -3
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +11 -2
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +39 -3
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +37 -3
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +4 -12
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +2 -1
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +765 -3
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +23 -3
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/processor/gossipHandlers.js +2 -2
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/package.json +14 -14
- package/src/api/impl/beacon/pool/index.ts +0 -52
- package/src/api/impl/beacon/state/index.ts +52 -1
- package/src/api/impl/beacon/state/utils.ts +57 -4
- package/src/api/impl/validator/index.ts +45 -2
- package/src/chain/produceBlock/produceBlockBody.ts +9 -17
- package/src/network/gossip/gossipsub.ts +2 -1
- package/src/network/gossip/topic.ts +28 -4
- package/src/network/processor/gossipHandlers.ts +1 -1
|
@@ -65,6 +65,8 @@ import {
|
|
|
65
65
|
AttestationError,
|
|
66
66
|
AttestationErrorCode,
|
|
67
67
|
GossipAction,
|
|
68
|
+
ProposerPreferencesError,
|
|
69
|
+
ProposerPreferencesErrorCode,
|
|
68
70
|
SyncCommitteeError,
|
|
69
71
|
SyncCommitteeErrorCode,
|
|
70
72
|
} from "../../../chain/errors/index.js";
|
|
@@ -74,6 +76,7 @@ import {BlockType, ProduceFullDeneb, ProduceFullGloas} from "../../../chain/prod
|
|
|
74
76
|
import {RegenCaller} from "../../../chain/regen/index.js";
|
|
75
77
|
import {CheckpointHex} from "../../../chain/stateCache/types.js";
|
|
76
78
|
import {validateApiAggregateAndProof} from "../../../chain/validation/index.js";
|
|
79
|
+
import {validateGossipProposerPreferences} from "../../../chain/validation/proposerPreferences.js";
|
|
77
80
|
import {validateSyncCommitteeGossipContributionAndProof} from "../../../chain/validation/syncCommitteeContributionAndProof.js";
|
|
78
81
|
import {ZERO_HASH} from "../../../constants/index.js";
|
|
79
82
|
import {BuilderStatus, NoBidReceived} from "../../../execution/builder/http.js";
|
|
@@ -1118,8 +1121,8 @@ export function getValidatorApi(
|
|
|
1118
1121
|
|
|
1119
1122
|
const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
|
|
1120
1123
|
if (!block) {
|
|
1121
|
-
// No block is seen at slot. Return
|
|
1122
|
-
|
|
1124
|
+
// No canonical block is seen at slot. Return 204 so vc can skip casting payload attestation.
|
|
1125
|
+
return {data: undefined, meta: {version: fork}, status: 204};
|
|
1123
1126
|
}
|
|
1124
1127
|
|
|
1125
1128
|
const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
|
|
@@ -1771,6 +1774,46 @@ export function getValidatorApi(
|
|
|
1771
1774
|
});
|
|
1772
1775
|
},
|
|
1773
1776
|
|
|
1777
|
+
async submitProposerPreferences({signedProposerPreferences}) {
|
|
1778
|
+
const failures: FailureList = [];
|
|
1779
|
+
|
|
1780
|
+
await Promise.all(
|
|
1781
|
+
signedProposerPreferences.map(async (signed, i) => {
|
|
1782
|
+
try {
|
|
1783
|
+
await validateGossipProposerPreferences(chain, signed);
|
|
1784
|
+
|
|
1785
|
+
chain.proposerPreferencesPool.add(signed);
|
|
1786
|
+
await network.publishProposerPreferences(signed);
|
|
1787
|
+
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
1788
|
+
version: config.getForkName(signed.message.proposalSlot),
|
|
1789
|
+
data: signed,
|
|
1790
|
+
});
|
|
1791
|
+
} catch (e) {
|
|
1792
|
+
const logCtx = {
|
|
1793
|
+
slot: signed.message.proposalSlot,
|
|
1794
|
+
validatorIndex: signed.message.validatorIndex,
|
|
1795
|
+
dependentRoot: toRootHex(signed.message.dependentRoot),
|
|
1796
|
+
};
|
|
1797
|
+
|
|
1798
|
+
if (e instanceof ProposerPreferencesError && e.type.code === ProposerPreferencesErrorCode.ALREADY_KNOWN) {
|
|
1799
|
+
logger.debug("Ignoring known signed proposer preferences", logCtx);
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
failures.push({index: i, message: (e as Error).message});
|
|
1804
|
+
logger.verbose(`Error on submitProposerPreferences [${i}]`, logCtx, e as Error);
|
|
1805
|
+
if (e instanceof ProposerPreferencesError && e.action === GossipAction.REJECT) {
|
|
1806
|
+
chain.persistInvalidSszValue(ssz.gloas.SignedProposerPreferences, signed, "api_reject");
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
})
|
|
1810
|
+
);
|
|
1811
|
+
|
|
1812
|
+
if (failures.length > 0) {
|
|
1813
|
+
throw new IndexedError("Error processing signed proposer preferences", failures);
|
|
1814
|
+
}
|
|
1815
|
+
},
|
|
1816
|
+
|
|
1774
1817
|
async getExecutionPayloadEnvelope({slot, beaconBlockRoot}) {
|
|
1775
1818
|
const fork = config.getForkName(slot);
|
|
1776
1819
|
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
ValidatorIndex,
|
|
44
44
|
Wei,
|
|
45
45
|
altair,
|
|
46
|
+
bellatrix,
|
|
46
47
|
capella,
|
|
47
48
|
deneb,
|
|
48
49
|
electra,
|
|
@@ -830,28 +831,19 @@ export function getPayloadAttributesForSSE(
|
|
|
830
831
|
feeRecipient,
|
|
831
832
|
});
|
|
832
833
|
|
|
833
|
-
|
|
834
|
-
if (isForkPostGloas(fork)) {
|
|
835
|
-
const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
|
|
836
|
-
toRootHex(parentBlockRoot),
|
|
837
|
-
toRootHex(parentBlockHash)
|
|
838
|
-
);
|
|
839
|
-
if (parentBlock?.executionPayloadBlockHash == null) {
|
|
840
|
-
throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
|
|
841
|
-
}
|
|
842
|
-
parentBlockNumber = parentBlock.executionPayloadNumber;
|
|
843
|
-
} else {
|
|
844
|
-
parentBlockNumber = prepareState.payloadBlockNumber;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
const ssePayloadAttributes: SSEPayloadAttributes = {
|
|
834
|
+
const ssePayloadAttributes = {
|
|
848
835
|
proposerIndex: prepareState.getBeaconProposer(prepareSlot),
|
|
849
836
|
proposalSlot: prepareSlot,
|
|
850
|
-
parentBlockNumber,
|
|
851
837
|
parentBlockRoot,
|
|
852
838
|
parentBlockHash,
|
|
853
839
|
payloadAttributes,
|
|
854
|
-
};
|
|
840
|
+
} as SSEPayloadAttributes;
|
|
841
|
+
|
|
842
|
+
if (!isForkPostGloas(fork)) {
|
|
843
|
+
// Removed in Gloas, builders can get the block number from the EL via the block hash if required
|
|
844
|
+
(ssePayloadAttributes as bellatrix.SSEPayloadAttributes).parentBlockNumber = prepareState.payloadBlockNumber;
|
|
845
|
+
}
|
|
846
|
+
|
|
855
847
|
return ssePayloadAttributes;
|
|
856
848
|
}
|
|
857
849
|
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
computeGossipPeerScoreParams,
|
|
36
36
|
gossipScoreThresholds,
|
|
37
37
|
} from "./scoringParameters.js";
|
|
38
|
-
import {GossipTopicCache, getCoreTopicsAtFork, stringifyGossipTopic} from "./topic.js";
|
|
38
|
+
import {GossipTopicCache, getAllowedTopics, getCoreTopicsAtFork, stringifyGossipTopic} from "./topic.js";
|
|
39
39
|
|
|
40
40
|
/** As specified in https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md */
|
|
41
41
|
const GOSSIPSUB_HEARTBEAT_INTERVAL = 0.7 * 1000;
|
|
@@ -140,6 +140,7 @@ export class Eth2Gossipsub {
|
|
|
140
140
|
const gossipsubInstance = gossipsub({
|
|
141
141
|
globalSignaturePolicy: StrictNoSign,
|
|
142
142
|
allowPublishToZeroTopicPeers: allowPublishToZeroPeers,
|
|
143
|
+
allowedTopics: getAllowedTopics(networkConfig),
|
|
143
144
|
D: gossipsubD ?? GOSSIP_D,
|
|
144
145
|
Dlo: gossipsubDLow ?? GOSSIP_D_LOW,
|
|
145
146
|
Dhi: gossipsubDHigh ?? GOSSIP_D_HIGH,
|
|
@@ -246,7 +246,7 @@ export function parseGossipTopic(forkDigestContext: ForkDigestContext, topicStr:
|
|
|
246
246
|
export function getCoreTopicsAtFork(
|
|
247
247
|
networkConfig: NetworkConfig,
|
|
248
248
|
fork: ForkName,
|
|
249
|
-
opts: {subscribeAllSubnets?: boolean; disableLightClientServer?: boolean}
|
|
249
|
+
opts: {subscribeAllSubnets?: boolean; subscribeAllColumnSubnets?: boolean; disableLightClientServer?: boolean}
|
|
250
250
|
): GossipTopicTypeMap[keyof GossipTopicTypeMap][] {
|
|
251
251
|
// Common topics for all forks
|
|
252
252
|
const topics: GossipTopicTypeMap[keyof GossipTopicTypeMap][] = [
|
|
@@ -266,7 +266,7 @@ export function getCoreTopicsAtFork(
|
|
|
266
266
|
|
|
267
267
|
// After fulu also track data_column_sidecar_{index}
|
|
268
268
|
if (ForkSeq[fork] >= ForkSeq.fulu) {
|
|
269
|
-
topics.push(...getDataColumnSidecarTopics(networkConfig));
|
|
269
|
+
topics.push(...getDataColumnSidecarTopics(networkConfig, opts.subscribeAllColumnSubnets));
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
// After Deneb and before Fulu also track blob_sidecar_{subnet_id}
|
|
@@ -309,15 +309,39 @@ export function getCoreTopicsAtFork(
|
|
|
309
309
|
return topics;
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Build the complete set of valid gossip topic strings across every fork boundary.
|
|
314
|
+
*/
|
|
315
|
+
export function getAllowedTopics(networkConfig: NetworkConfig): Set<string> {
|
|
316
|
+
const {config} = networkConfig;
|
|
317
|
+
const allowedTopics = new Set<string>();
|
|
318
|
+
|
|
319
|
+
for (const boundary of config.forkBoundariesAscendingEpochOrder) {
|
|
320
|
+
const topics = getCoreTopicsAtFork(networkConfig, boundary.fork, {
|
|
321
|
+
subscribeAllSubnets: true,
|
|
322
|
+
subscribeAllColumnSubnets: true,
|
|
323
|
+
disableLightClientServer: false,
|
|
324
|
+
});
|
|
325
|
+
for (const topic of topics) {
|
|
326
|
+
allowedTopics.add(stringifyGossipTopic(config, {...topic, boundary}));
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return allowedTopics;
|
|
331
|
+
}
|
|
332
|
+
|
|
312
333
|
/**
|
|
313
334
|
* Pick data column subnets to subscribe to post-fulu.
|
|
314
335
|
*/
|
|
315
336
|
export function getDataColumnSidecarTopics(
|
|
316
|
-
networkConfig: NetworkConfig
|
|
337
|
+
networkConfig: NetworkConfig,
|
|
338
|
+
subscribeAllColumnSubnets = false
|
|
317
339
|
): GossipTopicTypeMap[keyof GossipTopicTypeMap][] {
|
|
318
340
|
const topics: GossipTopicTypeMap[keyof GossipTopicTypeMap][] = [];
|
|
319
341
|
|
|
320
|
-
const subnets =
|
|
342
|
+
const subnets = subscribeAllColumnSubnets
|
|
343
|
+
? Array.from({length: networkConfig.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT}, (_, i) => i)
|
|
344
|
+
: networkConfig.custodyConfig.sampledSubnets;
|
|
321
345
|
for (const subnet of subnets) {
|
|
322
346
|
topics.push({type: GossipType.data_column_sidecar, subnet});
|
|
323
347
|
}
|
|
@@ -1274,7 +1274,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1274
1274
|
await validateGossipProposerPreferences(chain, signedProposerPreferences);
|
|
1275
1275
|
|
|
1276
1276
|
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
1277
|
-
version:
|
|
1277
|
+
version: config.getForkName(signedProposerPreferences.message.proposalSlot),
|
|
1278
1278
|
data: signedProposerPreferences,
|
|
1279
1279
|
});
|
|
1280
1280
|
},
|