3.3 Code Lodestar Gossip Handling
Gossipsub#
'sub' means pubsub protocol and 'gossipsub' means a pubsub protocol built on gossip protocol. Its code is https://github.com/ChainSafe/lodestar/blob/v1.5.1/packages/beacon-node/src/network/gossip/gossipsub.ts and it was initialized by:
this.gossip = new Eth2Gossipsub(opts, {
config,
libp2p,
logger,
metrics,
signal,
gossipHandlers: gossipHandlers ?? getGossipHandlers({chain, config, logger, network: this, metrics}, opts),
eth2Context: {
activeValidatorCount: chain.getHeadState().epochCtx.currentShuffling.activeIndices.length,
currentSlot: this.clock.currentSlot,
currentEpoch: this.clock.currentEpoch,
},
peersData: this.peersData,
});
Its core logic is in https://github.com/ChainSafe/lodestar/blob/v1.5.1/packages/beacon-node/src/network/gossip/handlers/index.ts - function getGossipHandlers
, where it defines the logic for each message, such as GossipType.beacon_block
or GossipType.beacon_block_and_blobs_sidecar
. A lot of the topics are defined here in 'phase0'. Some newer ones are defined in later upgrades.
Attestation Subnets(attnets) and Sync Subnets(syncnets)#
Attestations are aggregated in subnets before broadcasted globally. The gossip topic beacon_attestation_{subnet_id}
segregates clients into different subnets. Code is in https://github.com/ChainSafe/lodestar/blob/v1.5.1/packages/beacon-node/src/network/subnets/attnetsService.ts
The 'sync subnets' is in https://github.com/ChainSafe/lodestar/blob/v1.5.1/packages/beacon-node/src/network/subnets/syncnetsService.ts and it looks like simplified attnetsService.ts
.
The subnets subscription is called in https://github.com/ChainSafe/lodestar/blob/v1.5.1/packages/beacon-node/src/network/network.ts (the code below is simplified to focus on attnetsService) at the start of each epoch and during each network upgrades, e.g. altair, deneb, etc. It does some polyfills when Ethereum decides to change topic name, e.g. from beacon_block
to beacon_block_and_blobs_sidecar
.
private onEpoch = (epoch: Epoch): void => {
try {
const activeForks = getActiveForks(this.config, epoch);
for (let i = 0; i < activeForks.length; i++) {
if (activeForks[i + 1]) {
const prevFork = activeForks[i];
const nextFork = activeForks[i + 1];
const forkEpoch = this.config.forks[nextFork].epoch;
// Before fork transition
if (epoch === forkEpoch - FORK_EPOCH_LOOKAHEAD) {
this.attnetsService.subscribeSubnetsToNextFork(nextFork);
this.syncnetsService.subscribeSubnetsToNextFork(nextFork);
}
// After fork transition
if (epoch === forkEpoch + FORK_EPOCH_LOOKAHEAD) {
this.attnetsService.unsubscribeSubnetsFromPrevFork(prevFork);
this.syncnetsService.unsubscribeSubnetsFromPrevFork(prevFork);
}
}
}
} catch (e) {
this.logger.error("Error on BeaconGossipHandler.onEpoch", {epoch}, e as Error);
}
};
attnetsService
has 2 periodic functions itself: onSlot
and onEpoch
. onSlot
cleans up unused subnets. onEpoch
cleans up offline validators. The difference in known has an influence in the next subnet subscription (in function rebalanceRandomSubnets
). See more in specs:
ATTESTATION_SUBNET_COUNT
: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#why-are-there-attestation_subnet_count-attestation-subnets- Attestation subnet subscription: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#attestation-subnet-subscription