@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
110 lines • 5.53 kB
JavaScript
import { TopicValidatorResult } from "@libp2p/interface";
import { AttestationError, GossipAction, GossipActionError } from "../../chain/errors/index.js";
/**
* Similar to getGossipValidatorFn but return a function to accept a batch of beacon_attestation messages
* with the same attestation data
*/
export function getGossipValidatorBatchFn(gossipHandlers, modules) {
const { logger, metrics } = modules;
return async function gossipValidatorBatchFn(messageInfos) {
// all messageInfos have same topic type
const type = messageInfos[0].topic.type;
try {
const results = await gossipHandlers[type](messageInfos.map((messageInfo) => ({
gossipData: {
serializedData: messageInfo.msg.data,
msgSlot: messageInfo.msgSlot,
indexed: messageInfo.indexed,
},
topic: messageInfo.topic,
peerIdStr: messageInfo.propagationSource,
seenTimestampSec: messageInfo.seenTimestampSec,
})));
return results.map((e) => {
if (e == null) {
return TopicValidatorResult.Accept;
}
if (!(e instanceof AttestationError)) {
logger.debug(`Gossip batch validation ${type} threw a non-AttestationError`, {}, e);
metrics?.networkProcessor.gossipValidationIgnore.inc({ topic: type });
return TopicValidatorResult.Ignore;
}
switch (e.action) {
case GossipAction.IGNORE:
metrics?.networkProcessor.gossipValidationIgnore.inc({ topic: type });
// only beacon_attestation topic is validated in batch
metrics?.networkProcessor.gossipAttestationIgnoreByReason.inc({ reason: e.type.code });
return TopicValidatorResult.Ignore;
case GossipAction.REJECT:
metrics?.networkProcessor.gossipValidationReject.inc({ topic: type });
// only beacon_attestation topic is validated in batch
metrics?.networkProcessor.gossipAttestationRejectByReason.inc({ reason: e.type.code });
logger.debug(`Gossip validation ${type} rejected`, {}, e);
return TopicValidatorResult.Reject;
}
});
}
catch (e) {
// Don't expect error here
logger.debug(`Gossip batch validation ${type} threw an error`, {}, e);
const results = [];
for (let i = 0; i < messageInfos.length; i++) {
results.push(TopicValidatorResult.Ignore);
}
return results;
}
};
}
/**
* Returns a GossipSub validator function from a GossipHandlerFn. GossipHandlerFn may throw GossipActionError if one
* or more validation conditions from the consensus-specs#p2p-interface are not satisfied.
*
* This function receives a string topic and a binary message `InMessage` and deserializes both using caches.
* - The topic string should be known in advance and pre-computed
* - The message.data should already by uncompressed when computing its msgID
*
* All logging and metrics associated with gossip object validation should happen in this function. We want to know
* - In debug logs what objects are we processing, the result and some succint metadata
* - In metrics what's the throughput and ratio of accept/ignore/reject per type
*
* @see getGossipHandlers for reasoning on why GossipHandlerFn are used for gossip validation.
*/
export function getGossipValidatorFn(gossipHandlers, modules) {
const { logger, metrics } = modules;
return async function gossipValidatorFn({ topic, msg, propagationSource, seenTimestampSec, msgSlot }) {
const type = topic.type;
try {
await gossipHandlers[type]({
gossipData: { serializedData: msg.data, msgSlot },
topic,
peerIdStr: propagationSource,
seenTimestampSec,
});
metrics?.networkProcessor.gossipValidationAccept.inc({ topic: type });
return TopicValidatorResult.Accept;
}
catch (e) {
if (!(e instanceof GossipActionError)) {
// not deserve to log error here, it looks too dangerous to users
logger.debug(`Gossip validation ${type} threw a non-GossipActionError`, {}, e);
return TopicValidatorResult.Ignore;
}
// Metrics on specific error reason
// Note: LodestarError.code are bounded pre-declared error messages, not from arbitrary error.message
metrics?.networkProcessor.gossipValidationError.inc({
topic: type,
error: e.type.code,
});
switch (e.action) {
case GossipAction.IGNORE:
metrics?.networkProcessor.gossipValidationIgnore.inc({ topic: type });
return TopicValidatorResult.Ignore;
case GossipAction.REJECT:
metrics?.networkProcessor.gossipValidationReject.inc({ topic: type });
logger.debug(`Gossip validation ${type} rejected`, {}, e);
return TopicValidatorResult.Reject;
}
}
};
}
//# sourceMappingURL=gossipValidatorFn.js.map