UNPKG

xud

Version:
266 lines (265 loc) 11.8 kB
/// <reference types="node" /> import { EventEmitter } from 'events'; import { Socket } from 'net'; import { DisconnectionReason, ReputationEvent, SwapClientType } from '../constants/enums'; import Logger from '../Logger'; import NodeKey from '../nodekey/NodeKey'; import { OutgoingOrder } from '../orderbook/types'; import Network from './Network'; import { Packet } from './packets'; import { ResponseType } from './packets/Packet'; import * as packets from './packets/types'; import { Address, NodeConnectionInfo, NodeState } from './types'; /** Key info about a peer for display purposes */ declare type PeerInfo = { address: string; nodePubKey?: string; alias?: string; inbound: boolean; pairs?: string[]; xudVersion?: string; secondsConnected: number; lndPubKeys?: { [currency: string]: string | undefined; }; connextIdentifier?: string; }; interface Peer { on(event: 'packet', listener: (packet: Packet) => void): this; on(event: 'reputation', listener: (event: ReputationEvent) => void): this; /** Adds a listener to be called when the peer's advertised but inactive pairs should be verified. */ on(event: 'verifyPairs', listener: () => void): this; /** Adds a listener to be called when a previously active pair is dropped by the peer or deactivated. */ on(event: 'pairDropped', listener: (pairId: string) => void): this; on(event: 'nodeStateUpdate', listener: () => void): this; once(event: 'close', listener: () => void): this; emit(event: 'connect'): boolean; emit(event: 'reputation', reputationEvent: ReputationEvent): boolean; emit(event: 'close'): boolean; emit(event: 'packet', packet: Packet): boolean; /** Notifies listeners that the peer's advertised but inactive pairs should be verified. */ emit(event: 'verifyPairs'): boolean; /** Notifies listeners that a previously active pair was dropped by the peer or deactivated. */ emit(event: 'pairDropped', pairId: string): boolean; emit(event: 'nodeStateUpdate'): boolean; } /** Represents a remote peer and manages a TCP socket and incoming/outgoing communication with that peer. */ declare class Peer extends EventEmitter { private logger; address: Address; inbound: boolean; /** The reason this peer disconnected from us. */ recvDisconnectionReason?: DisconnectionReason; /** The reason we told this peer we disconnected from it. */ sentDisconnectionReason?: DisconnectionReason; expectedNodePubKey?: string; /** Whether the peer is included in the p2p pool list of peers and will receive broadcasted packets. */ active: boolean; /** Timer to periodically call getNodes #402 */ discoverTimer?: NodeJS.Timer; /** * Currencies that we cannot swap because we are missing a swap client identifier or because the * peer's token identifier for this currency does not match ours - for example this may happen * because a peer is using a different token contract address for a currency than we are. */ disabledCurrencies: Set<string>; /** Interval to check required responses from peer. */ static readonly STALL_INTERVAL = 5000; private status; /** Trading pairs advertised by this peer which we have verified that we can swap. */ private activePairs; /** Currencies that we have verified we can swap with this peer. */ private activeCurrencies; private socket?; private readonly parser; /** Timer to retry connection to peer after the previous attempt failed. */ private retryConnectionTimer?; private stallTimer?; private pingTimer?; private checkPairsTimer?; private readonly responseMap; /** The epoch time in ms when we connected to this peer. */ private connectTime; private connectionRetriesRevoked; /** The version of xud this peer is using. */ private _version?; /** The node pub key of this peer. */ private _nodePubKey?; private _alias?; private nodeState?; private sessionInitPacket?; private outEncryptionKey?; private readonly network; private readonly framer; /** Interval for pinging peers. */ private static readonly PING_INTERVAL; /** Interval for checking if we can reactivate any inactive pairs with peers. */ private static readonly CHECK_PAIRS_INTERVAL; /** Response timeout for response packets. */ private static readonly RESPONSE_TIMEOUT; /** Connection retries min delay. */ private static readonly CONNECTION_RETRIES_MIN_DELAY; /** Connection retries max delay. */ private static readonly CONNECTION_RETRIES_MAX_DELAY; /** Connection retries max period. */ private static readonly CONNECTION_RETRIES_MAX_PERIOD; /** The version of xud this peer is using, or an empty string if it is still not known. */ get version(): string; /** The hex-encoded node public key for this peer, or undefined if it is still not known. */ get nodePubKey(): string | undefined; set nodePubKey(nodePubKey: string | undefined); get alias(): string | undefined; get label(): string; get addresses(): Address[] | undefined; get connextIdentifier(): string | undefined; /** Returns a list of trading pairs advertised by this peer. */ get advertisedPairs(): string[]; get connected(): boolean; get info(): PeerInfo; /** * @param address The socket address for the connection to this peer. */ constructor(logger: Logger, address: Address, network: Network); /** * Creates a Peer from an inbound socket connection. */ static fromInbound: (socket: Socket, logger: Logger, network: Network) => Peer; getAdvertisedCurrencies: () => Set<string>; getLndPubKey(currency?: string): string | undefined; getIdentifier: (clientType: SwapClientType, currency?: string | undefined) => string | undefined; getTokenIdentifier: (currency: string) => string | undefined; getStatus: () => string; /** * Prepares a peer for use by establishing a socket connection and beginning the handshake. * @returns the session init packet from beginning the handshake */ beginOpen: ({ ownNodeState, ownNodeKey, ownVersion, expectedNodePubKey, retryConnecting, torport, }: { /** Our node state data to send to the peer. */ ownNodeState: NodeState; /** Our identity node key. */ ownNodeKey: NodeKey; /** The version of xud we are running. */ ownVersion: string; /** The expected nodePubKey of the node we are opening a connection with. */ expectedNodePubKey?: string | undefined; /** Whether to retry to connect upon failure. */ retryConnecting?: boolean | undefined; /** Port that Tor's exposed SOCKS5 proxy is listening on. */ torport: number; }) => Promise<packets.SessionInitPacket>; /** * Finishes opening a peer for use by marking the peer as opened, completing the handshake, * and setting up the ping packet timer. * @param ownNodeState our node state data to send to the peer * @param ownNodeKey our identity node key * @param ownVersion the version of xud we are running * @param sessionInit the session init packet we received when beginning the handshake */ completeOpen: (ownNodeState: NodeState, ownNodeKey: NodeKey, ownVersion: string, sessionInit: packets.SessionInitPacket) => Promise<void>; /** * Close a peer by ensuring the socket is destroyed and terminating all timers. */ close: (reason?: DisconnectionReason | undefined, reasonPayload?: string | undefined) => Promise<void>; revokeConnectionRetries: () => void; sendPacket: (packet: Packet) => Promise<void>; sendOrders: (orders: OutgoingOrder[], reqId: string) => Promise<void>; /** Sends a [[NodesPacket]] containing node connection info to this peer. */ sendNodes: (nodes: NodeConnectionInfo[], reqId: string) => Promise<void>; deactivateCurrency: (currency: string) => void; activateCurrency: (currency: string) => Set<string>; disableCurrency: (currency: string) => void; enableCurrency: (currency: string) => void; /** * Deactivates a trading pair with this peer. */ deactivatePair: (pairId: string) => void; /** * Activates a trading pair with this peer. */ activatePair: (pairId: string) => Promise<void>; isPairActive: (pairId: string) => boolean; isCurrencyActive: (currency: string) => boolean; /** * Gets lnd client's listening uris for the provided currency. * @param currency */ getLndUris(currency: string): string[] | undefined; /** * Ensure we are connected (for inbound connections) or listen for the `connect` socket event (for outbound connections) * and set the [[connectTime]] timestamp. If an outbound connection attempt errors or times out, throw an error. */ private initConnection; private initStall; /** * Waits for a packet to be received from peer. * @returns A promise that is resolved once the packet is received or rejects on timeout. */ wait: (reqId: string, resType: ResponseType, timeout?: number | undefined, cb?: ((packet: Packet) => void) | undefined) => Promise<Packet>; private waitSessionInit; /** * Potentially timeout peer if it hasn't responded. */ private checkTimeout; /** * Wait for a packet to be received from peer. */ private addResponseTimeout; private getOrAddPendingResponseEntry; /** * Fulfill a pending response entry for solicited responses, penalize unsolicited responses. * @returns false if no pending response entry exists for the provided key, otherwise true */ private fulfillResponseEntry; /** * Binds listeners to a newly connected socket for `error`, `close`, and `data` events. */ private bindSocket; private bindParser; /** Checks if a given packet is solicited and fulfills the pending response entry if it's a response. */ private isPacketSolicited; private handlePacket; /** * Authenticates the identity of a peer with a [[SessionInitPacket]] and sets the peer's node state. * Throws an error and closes the peer if authentication fails. * @param packet the session init packet * @param nodePubKey our node pub key * @param expectedNodePubKey the expected node pub key of the sender of the init packet */ private authenticateSessionInit; /** * Sets public key and alias for this node together so that they are always in sync. */ setIdentifiers(nodePubKey: string): void; /** * Sends a [[SessionInitPacket]] and waits for a [[SessionAckPacket]]. */ private initSession; /** * Sends a [[SessionAckPacket]] in response to a given [[SessionInitPacket]]. */ private ackSession; /** * Begins the handshake by waiting for a [[SessionInitPacket]] as well as sending our own * [[SessionInitPacket]] first if we are the outbound peer. * @returns the session init packet we receive */ private beginHandshake; /** * Completes the handshake by sending the [[SessionAckPacket]] and our [[SessionInitPacket]] if it * has not been sent already, as is the case with inbound peers. */ private completeHandshake; private sendPing; sendGetNodes: () => Promise<packets.GetNodesPacket>; discoverNodes: () => Promise<number>; private sendPong; private handlePing; private createSessionInitPacket; private handleDisconnecting; private handleSessionInit; private handleNodeStateUpdate; private setOutEncryption; private setInEncryption; } export default Peer; export { PeerInfo };