UNPKG

libp2p-gossipsub

Version:
105 lines (104 loc) 4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.IWantTracer = void 0; const constants_1 = require("./constants"); const utils_1 = require("./utils"); const pubsubErrors = require("libp2p-interfaces/src/pubsub/errors"); const { ERR_INVALID_SIGNATURE, ERR_MISSING_SIGNATURE } = pubsubErrors.codes; /** * IWantTracer is an internal tracer that tracks IWANT requests in order to penalize * peers who don't follow up on IWANT requests after an IHAVE advertisement. * The tracking of promises is probabilistic to avoid using too much memory. * * Note: Do not confuse these 'promises' with JS Promise objects. * These 'promises' are merely expectations of a peer's behavior. */ class IWantTracer { constructor() { this.promises = new Map(); } /** * Track a promise to deliver a message from a list of msgIds we are requesting * @param {string} p peer id * @param {string[]} msgIds * @returns {void} */ addPromise(p, msgIds) { // pick msgId randomly from the list const ix = Math.floor(Math.random() * msgIds.length); const msgId = msgIds[ix]; const msgIdStr = utils_1.messageIdToString(msgId); let peers = this.promises.get(msgIdStr); if (!peers) { peers = new Map(); this.promises.set(msgIdStr, peers); } if (!peers.has(p)) { peers.set(p, Date.now() + constants_1.GossipsubIWantFollowupTime); } } /** * Returns the number of broken promises for each peer who didn't follow up on an IWANT request. * @returns {Map<string, number>} */ getBrokenPromises() { const now = Date.now(); const result = new Map(); this.promises.forEach((peers, msgId) => { peers.forEach((expire, p) => { // the promise has been broken if (expire < now) { // add 1 to result result.set(p, (result.get(p) || 0) + 1); // delete from tracked promises peers.delete(p); } }); // clean up empty promises for a msgId if (!peers.size) { this.promises.delete(msgId); } }); return result; } /** * Someone delivered a message, stop tracking promises for it * @param {string} msgIdStr * @returns {Promise<void>} */ deliverMessage(msgIdStr) { return __awaiter(this, void 0, void 0, function* () { this.promises.delete(msgIdStr); }); } /** * A message got rejected, so we can stop tracking promises and let the score penalty apply from invalid message delivery, * unless its an obviously invalid message. * @param {string} msgIdStr * @param {string} reason * @returns {Promise<void>} */ rejectMessage(msgIdStr, reason) { return __awaiter(this, void 0, void 0, function* () { switch (reason) { case ERR_INVALID_SIGNATURE: case ERR_MISSING_SIGNATURE: return; } this.promises.delete(msgIdStr); }); } clear() { this.promises.clear(); } } exports.IWantTracer = IWantTracer;