@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
69 lines • 2.9 kB
JavaScript
import { MapDef, pruneSetToMax } from "@lodestar/utils";
import { DEFAULT_SCORE, MAX_ENTRIES, MAX_SCORE, MIN_SCORE, SCORE_THRESHOLD } from "./constants.js";
import { PeerAction } from "./interface.js";
import { MaxScore, RealScore } from "./score.js";
import { scoreToState } from "./utils.js";
const peerActionScore = {
[PeerAction.Fatal]: -(MAX_SCORE - MIN_SCORE),
[PeerAction.LowToleranceError]: -10,
[PeerAction.MidToleranceError]: -5,
[PeerAction.HighToleranceError]: -1,
};
/**
* A peer's score (perceived potential usefulness).
* This simplistic version consists of a global score per peer which decays to 0 over time.
* The decay rate applies equally to positive and negative scores.
* Peer cool-down period will be checked before dialing and will only be dialed if score is not waiting to decay
*/
export class PeerRpcScoreStore {
// TODO: Persist scores, at least BANNED status to disk
constructor(opts = {}, metrics = null) {
this.metrics = metrics;
this.scores = opts.disablePeerScoring ? new MapDef(() => new MaxScore()) : new MapDef(() => new RealScore());
}
getScore(peer) {
return this.scores.get(peer.toString())?.getScore() ?? DEFAULT_SCORE;
}
getGossipScore(peer) {
return this.scores.get(peer.toString())?.getGossipScore() ?? DEFAULT_SCORE;
}
getScoreState(peer) {
return scoreToState(this.getScore(peer));
}
isCoolingDown(peerIdStr) {
return this.scores.get(peerIdStr)?.isCoolingDown() ?? false;
}
dumpPeerScoreStats() {
return Array.from(this.scores.entries()).map(([peerId, peerScore]) => ({ peerId, ...peerScore.getStat() }));
}
applyAction(peer, action, actionName) {
const peerScore = this.scores.getOrDefault(peer.toString());
peerScore.add(peerActionScore[action]);
this.metrics?.peersReportPeerCount.inc({ reason: actionName });
}
/**
* Apply a reconnection cool-down period to prevent automatic reconnection. Sets peer
* banning period and updates gossip score to -1 so next update removes the negative
* score
*/
applyReconnectionCoolDown(peer, reason) {
const peerScore = this.scores.getOrDefault(peer);
return peerScore.applyReconnectionCoolDown(reason);
}
update() {
// Bound size of data structures
pruneSetToMax(this.scores, MAX_ENTRIES);
for (const [peerIdStr, peerScore] of this.scores) {
const newScore = peerScore.update();
// Prune scores below threshold
if (Math.abs(newScore) < SCORE_THRESHOLD) {
this.scores.delete(peerIdStr);
}
}
}
updateGossipsubScore(peerId, newScore, ignore) {
const peerScore = this.scores.getOrDefault(peerId);
peerScore.updateGossipsubScore(newScore, ignore);
}
}
//# sourceMappingURL=store.js.map