UNPKG

libp2p-gossipsub

Version:
403 lines (402 loc) 13.6 kB
/// <reference types="node" /> import Pubsub, { InMessage } from 'libp2p-interfaces/src/pubsub'; import { MessageCache } from './message-cache'; import { RPC, IRPC } from './message/rpc'; import { Heartbeat } from './heartbeat'; import { PeerScore, PeerScoreParams, PeerScoreThresholds } from './score'; import { IWantTracer } from './tracer'; import { AddrInfo, MessageIdFunction } from './interfaces'; import { SimpleTimeCache } from './utils/time-cache'; import { Debugger } from 'debug'; import Libp2p from 'libp2p'; import PeerStreams from 'libp2p-interfaces/src/pubsub/peer-streams'; import PeerId = require('peer-id'); interface GossipInputOptions { emitSelf: boolean; canRelayMessage: boolean; gossipIncoming: boolean; fallbackToFloodsub: boolean; floodPublish: boolean; doPX: boolean; msgIdFn: MessageIdFunction; fastMsgIdFn: FastMsgIdFn; messageCache: MessageCache; globalSignaturePolicy: 'StrictSign' | 'StrictNoSign' | undefined; scoreParams: Partial<PeerScoreParams>; scoreThresholds: Partial<PeerScoreThresholds>; directPeers: AddrInfo[]; /** * D sets the optimal degree for a Gossipsub topic mesh. */ D: number; /** * Dlo sets the lower bound on the number of peers we keep in a Gossipsub topic mesh. */ Dlo: number; /** * Dhi sets the upper bound on the number of peers we keep in a Gossipsub topic mesh. */ Dhi: number; /** * Dscore affects how peers are selected when pruning a mesh due to over subscription. */ Dscore: number; /** * Dout sets the quota for the number of outbound connections to maintain in a topic mesh. */ Dout: number; /** * Dlazy affects how many peers we will emit gossip to at each heartbeat. */ Dlazy: number; /** * heartbeatInterval is the time between heartbeats in milliseconds */ heartbeatInterval: number; /** * fanoutTTL controls how long we keep track of the fanout state. If it's been * fanoutTTL milliseconds since we've published to a topic that we're not subscribed to, * we'll delete the fanout map for that topic. */ fanoutTTL: number; /** * mcacheLength is the number of windows to retain full messages for IWANT responses */ mcacheLength: number; /** * mcacheGossip is the number of windows to gossip about */ mcacheGossip: number; /** * seenTTL is the number of milliseconds to retain message IDs in the seen cache */ seenTTL: number; } interface GossipOptions extends GossipInputOptions { scoreParams: PeerScoreParams; scoreThresholds: PeerScoreThresholds; } interface AcceptFromWhitelistEntry { /** number of messages accepted since recomputing the peer's score */ messagesAccepted: number; /** have to recompute score after this time */ acceptUntil: number; } declare type FastMsgIdFn = (msg: InMessage) => string; declare class Gossipsub extends Pubsub { peers: Map<string, PeerStreams>; direct: Set<string>; seenCache: SimpleTimeCache<void>; acceptFromWhitelist: Map<string, AcceptFromWhitelistEntry>; topics: Map<string, Set<string>>; mesh: Map<string, Set<string>>; fanout: Map<string, Set<string>>; lastpub: Map<string, number>; gossip: Map<string, RPC.IControlIHave[]>; control: Map<string, RPC.IControlMessage>; peerhave: Map<string, number>; iasked: Map<string, number>; backoff: Map<string, Map<string, number>>; outbound: Map<string, boolean>; defaultMsgIdFn: MessageIdFunction; getFastMsgIdStr: FastMsgIdFn | undefined; fastMsgIdCache: SimpleTimeCache<string> | undefined; messageCache: MessageCache; score: PeerScore; heartbeat: Heartbeat; heartbeatTicks: number; gossipTracer: IWantTracer; multicodecs: string[]; started: boolean; peerId: PeerId; subscriptions: Set<string>; _libp2p: Libp2p; _options: GossipOptions; _directPeerInitial: NodeJS.Timeout; log: Debugger & { err: Debugger; }; emit: (event: string | symbol, ...args: any[]) => boolean; static multicodec: string; /** * @param {Libp2p} libp2p * @param {Object} [options] * @param {boolean} [options.emitSelf = false] if publish should emit to self, if subscribed * @param {boolean} [options.canRelayMessage = false] - if can relay messages not subscribed * @param {boolean} [options.gossipIncoming = true] if incoming messages on a subscribed topic should be automatically gossiped * @param {boolean} [options.fallbackToFloodsub = true] if dial should fallback to floodsub * @param {boolean} [options.floodPublish = true] if self-published messages should be sent to all peers * @param {boolean} [options.doPX = false] whether PX is enabled; this should be enabled in bootstrappers and other well connected/trusted nodes. * @param {Object} [options.messageCache] override the default MessageCache * @param {FastMsgIdFn} [options.fastMsgIdFn] fast message id function * @param {string} [options.globalSignaturePolicy = "StrictSign"] signing policy to apply across all messages * @param {Object} [options.scoreParams] peer score parameters * @param {Object} [options.scoreThresholds] peer score thresholds * @param {AddrInfo[]} [options.directPeers] peers with which we will maintain direct connections * @constructor */ constructor(libp2p: Libp2p, options?: Partial<GossipInputOptions>); /** * Decode a Uint8Array into an RPC object * Overrided to use an extended protocol-specific protobuf decoder * @override * @param {Uint8Array} bytes * @returns {RPC} */ _decodeRpc(bytes: Uint8Array): RPC; /** * Encode an RPC object into a Uint8Array * Overrided to use an extended protocol-specific protobuf encoder * @override * @param {RPC} rpc * @returns {Uint8Array} */ _encodeRpc(rpc: RPC): Uint8Array; /** * Add a peer to the router * @override * @param {PeerId} peerId * @param {string} protocol * @returns {PeerStreams} */ _addPeer(peerId: PeerId, protocol: string): PeerStreams; /** * Removes a peer from the router * @override * @param {PeerId} peer * @returns {PeerStreams | undefined} */ _removePeer(peerId: PeerId): PeerStreams | undefined; /** * Handles an rpc request from a peer * * @override * @param {String} idB58Str * @param {PeerStreams} peerStreams * @param {RPC} rpc * @returns {Promise<boolean>} */ _processRpc(id: string, peerStreams: PeerStreams, rpc: RPC): Promise<boolean>; /** * Handles an rpc control message from a peer * @param {string} id peer id * @param {RPC.IControlMessage} controlMsg * @returns {void} */ _processRpcControlMessage(id: string, controlMsg: RPC.IControlMessage): Promise<void>; /** * Process incoming message, * emitting locally and forwarding on to relevant floodsub and gossipsub peers * @override * @param {InMessage} msg * @returns {Promise<void>} */ _processRpcMessage(msg: InMessage): Promise<void>; /** * Whether to accept a message from a peer * @override * @param {string} id * @returns {boolean} */ _acceptFrom(id: string): boolean; /** * Validate incoming message * @override * @param {InMessage} msg * @returns {Promise<void>} */ validate(msg: InMessage): Promise<void>; /** * Handles IHAVE messages * @param {string} id peer id * @param {Array<RPC.IControlIHave>} ihave * @returns {RPC.IControlIWant} */ _handleIHave(id: string, ihave: RPC.IControlIHave[]): RPC.IControlIWant[]; /** * Handles IWANT messages * Returns messages to send back to peer * @param {string} id peer id * @param {Array<RPC.IControlIWant>} iwant * @returns {Array<RPC.IMessage>} */ _handleIWant(id: string, iwant: RPC.IControlIWant[]): RPC.IMessage[]; /** * Handles Graft messages * @param {string} id peer id * @param {Array<RPC.IControlGraft>} graft * @return {Promise<RPC.IControlPrune[]>} */ _handleGraft(id: string, graft: RPC.IControlGraft[]): Promise<RPC.IControlPrune[]>; /** * Handles Prune messages * @param {string} id peer id * @param {Array<RPC.IControlPrune>} prune * @returns {void} */ _handlePrune(id: string, prune: RPC.IControlPrune[]): void; /** * Add standard backoff log for a peer in a topic * @param {string} id * @param {string} topic * @returns {void} */ _addBackoff(id: string, topic: string): void; /** * Add backoff expiry interval for a peer in a topic * @param {string} id * @param {string} topic * @param {number} interval backoff duration in milliseconds * @returns {void} */ _doAddBackoff(id: string, topic: string, interval: number): void; /** * Apply penalties from broken IHAVE/IWANT promises * @returns {void} */ _applyIwantPenalties(): void; /** * Clear expired backoff expiries * @returns {void} */ _clearBackoff(): void; /** * Maybe reconnect to direct peers * @returns {void} */ _directConnect(): void; /** * Maybe attempt connection given signed peer records * @param {RPC.IPeerInfo[]} peers * @returns {Promise<void>} */ _pxConnect(peers: RPC.IPeerInfo[]): Promise<void>; /** * Mounts the gossipsub protocol onto the libp2p node and sends our * our subscriptions to every peer connected * @override * @returns {Promise<void>} */ start(): Promise<void>; /** * Unmounts the gossipsub protocol and shuts down every connection * @override * @returns {Promise<void>} */ stop(): Promise<void>; /** * Connect to a peer using the gossipsub protocol * @param {string} id * @returns {void} */ _connect(id: string): void; /** * Subscribes to a topic * @override * @param {string} topic * @returns {void} */ subscribe(topic: string): void; /** * Unsubscribe to a topic * @override * @param {string} topic * @returns {void} */ unsubscribe(topic: string): void; /** * Join topic * @param {string} topic * @returns {void} */ join(topic: string): void; /** * Leave topic * @param {string} topic * @returns {void} */ leave(topic: string): void; /** * Return the canonical message-id of a message as a string * * If a fast message-id is set: Try 1. the application cache 2. the fast cache 3. `getMsgId()` * If a fast message-id is NOT set: Just `getMsgId()` * @param {InMessage} msg * @returns {Promise<string>} */ getCanonicalMsgIdStr(msg: InMessage): Promise<string>; /** * An application should override this function to return its cached message id string without computing it. * Return undefined if message id is not found. * If a fast message id function is not defined, this function is ignored. * @param {InMessage} msg * @returns {string | undefined} */ getCachedMsgIdStr(msg: InMessage): string | undefined; /** * Publish messages * * @override * @param {InMessage} msg * @returns {void} */ _publish(msg: InMessage): Promise<void>; /** * Sends a GRAFT message to a peer * @param {string} id peer id * @param {string} topic * @returns {void} */ _sendGraft(id: string, topic: string): void; /** * Sends a PRUNE message to a peer * @param {string} id peer id * @param {string} topic * @returns {Promise<void>} */ _sendPrune(id: string, topic: string): Promise<void>; /** * @override */ _sendRpc(id: string, outRpc: IRPC): void; _piggybackControl(id: string, outRpc: IRPC, ctrl: RPC.IControlMessage): void; _piggybackGossip(id: string, outRpc: IRPC, ihave: RPC.IControlIHave[]): void; /** * Send graft and prune messages * @param {Map<string, Array<string>>} tograft peer id => topic[] * @param {Map<string, Array<string>>} toprune peer id => topic[] */ _sendGraftPrune(tograft: Map<string, string[]>, toprune: Map<string, string[]>, noPX: Map<string, boolean>): Promise<void>; /** * Emits gossip to peers in a particular topic * @param {string} topic * @param {Set<string>} exclude peers to exclude * @returns {void} */ _emitGossip(topic: string, exclude: Set<string>): void; /** * Flush gossip and control messages */ _flush(): void; /** * Adds new IHAVE messages to pending gossip * @param {PeerStreams} peerStreams * @param {Array<RPC.IControlIHave>} controlIHaveMsgs * @returns {void} */ _pushGossip(id: string, controlIHaveMsgs: RPC.IControlIHave): void; /** * Returns the current time in milliseconds * @returns {number} */ _now(): number; /** * Make a PRUNE control message for a peer in a topic * @param {string} id * @param {string} topic * @param {boolean} doPX * @returns {Promise<RPC.IControlPrune>} */ _makePrune(id: string, topic: string, doPX: boolean): Promise<RPC.IControlPrune>; } export = Gossipsub;