From 0ff93dc705a6b94a2f79690c02d25bd0ad83c05f Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Thu, 25 Aug 2016 19:30:56 -0700 Subject: [PATCH] pool: refactor host and peer list. --- etc/sample.conf | 2 +- lib/http/rpc.js | 9 +- lib/net/packets.js | 20 ++++ lib/net/peer.js | 4 +- lib/net/pool.js | 222 ++++++++++++++++++++------------------------- lib/utils/ip.js | 5 +- 6 files changed, 132 insertions(+), 130 deletions(-) diff --git a/etc/sample.conf b/etc/sample.conf index d56b4771..06ca4f4a 100644 --- a/etc/sample.conf +++ b/etc/sample.conf @@ -35,7 +35,7 @@ index-address: false # Pool # selfish: false headers: false -compact: true +compact: false bip151: true # proxy-server: localhost # preferred-seed: seed.bitcoin.sipa.be diff --git a/lib/http/rpc.js b/lib/http/rpc.js index c831a23b..86c00bc1 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -11,6 +11,7 @@ var utils = require('../utils/utils'); var IP = require('../utils/ip'); var assert = utils.assert; var constants = bcoin.constants; +var NetworkAddress = bcoin.packets.NetworkAddress; var fs; try { @@ -383,7 +384,7 @@ RPC.prototype.addnode = function addnode(args, callback) { node = toString(args[0]); cmd = toString(args[1]); - host = bcoin.packets.NetworkAddress.fromHostname(node, this.network); + host = NetworkAddress.fromHostname(node, this.network); switch (cmd) { case 'add': @@ -392,7 +393,7 @@ RPC.prototype.addnode = function addnode(args, callback) { case 'remove': for (i = 0; i < this.pool.seeds.length; i++) { seed = this.pool.seeds[i]; - if (seed.host === host.host) { + if (seed.hostname === host.hostname) { this.pool.seeds.splice(i, 1); break; } @@ -412,7 +413,7 @@ RPC.prototype.disconnectnode = function disconnectnode(args, callback) { return callback(new RPCError('disconnectnode "node"')); node = toString(args[0]); - node = IP.normalize(node); + node = NetworkAddress.fromHostname(node, this.network); peer = this.pool.peers.get(node); if (peer) @@ -543,7 +544,7 @@ RPC.prototype.setban = function setban(args, callback) { } host = toString(args[0]); - ip = IP.normalize(host); + ip = NetworkAddress.fromHostname(host, this.network); switch (args[1]) { case 'add': diff --git a/lib/net/packets.js b/lib/net/packets.js index 1f086f43..cd645eee 100644 --- a/lib/net/packets.js +++ b/lib/net/packets.js @@ -896,6 +896,26 @@ NetworkAddress.prototype.hasWitness = function hasWitness() { return (this.services & constants.services.WITNESS) !== 0; }; +/** + * Set host. + * @param {String} host + */ + +NetworkAddress.prototype.setHost = function setHost(host) { + this.host = host; + this.hostname = IP.hostname(host, this.port); +}; + +/** + * Set port. + * @param {Number} port + */ + +NetworkAddress.prototype.setPort = function setPort(port) { + this.host = port; + this.hostname = IP.hostname(this.host, port); +}; + /** * Inspect the network address. * @returns {Object} diff --git a/lib/net/peer.js b/lib/net/peer.js index 0e46d618..f45dbf38 100644 --- a/lib/net/peer.js +++ b/lib/net/peer.js @@ -2259,7 +2259,7 @@ Peer.prototype.sendCompact = function sendCompact() { */ Peer.prototype.isMisbehaving = function isMisbehaving() { - return this.pool.hosts.isMisbehaving(this.host); + return this.pool.hosts.isMisbehaving(this); }; /** @@ -2268,7 +2268,7 @@ Peer.prototype.isMisbehaving = function isMisbehaving() { */ Peer.prototype.isIgnored = function isIgnored() { - return this.pool.hosts.isIgnored(this.host); + return this.pool.hosts.isIgnored(this); }; /** diff --git a/lib/net/pool.js b/lib/net/pool.js index 43df8be3..21c4fa9d 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -170,8 +170,7 @@ Pool.prototype._initOptions = function _initOptions() { this.address.ts = utils.now(); this.address.services = this.services; - this.address.port = this.port; - this.address.hostname = IP.hostname(this.address.host, this.port); + this.address.setPort(this.port); if (this.options.maxPeers != null) this.maxPeers = this.options.maxPeers; @@ -320,8 +319,7 @@ Pool.prototype._open = function _open(callback) { self.logger.error(err); if (ip) { - self.address.host = ip; - self.address.hostname = IP.hostname(ip, self.address.port); + self.address.setHost(ip); self.logger.info('External IP found: %s.', ip); } @@ -483,7 +481,7 @@ Pool.prototype.unlisten = function unlisten(callback) { */ Pool.prototype._handleLeech = function _handleLeech(socket) { - var hostname, host; + var hostname, addr; if (!socket.remoteAddress) { this.logger.debug('Ignoring disconnected leech.'); @@ -491,24 +489,22 @@ Pool.prototype._handleLeech = function _handleLeech(socket) { return; } - host = IP.normalize(socket.remoteAddress); + hostname = IP.hostname(socket.remoteAddress, socket.remotePort); + addr = NetworkAddress.fromHostname(hostname, this.network); if (this.peers.leeches.length >= this.maxLeeches) { - hostname = IP.hostname(host, socket.remotePort); this.logger.debug('Ignoring leech: too many leeches (%s).', hostname); socket.destroy(); return; } - if (this.hosts.isMisbehaving(host)) { - hostname = IP.hostname(host, socket.remotePort); + if (this.hosts.isMisbehaving(addr)) { this.logger.debug('Ignoring misbehaving leech (%s).', hostname); socket.destroy(); return; } - if (this.hosts.isIgnored(host)) { - hostname = IP.hostname(host, socket.remotePort); + if (this.hosts.isIgnored(addr)) { this.logger.debug('Ignoring leech (%s).', hostname); socket.destroy(); return; @@ -604,7 +600,7 @@ Pool.prototype.stopInterval = function stopInterval() { Pool.prototype.addLoader = function addLoader() { var self = this; - var peer, host; + var peer, addr; if (!this.loaded) return; @@ -614,8 +610,8 @@ Pool.prototype.addLoader = function addLoader() { return; } - host = this.getLoaderHost(); - peer = this.peers.get(host); + addr = this.getLoaderHost(); + peer = this.peers.get(addr); if (peer) { this.peers.repurpose(peer); @@ -627,7 +623,7 @@ Pool.prototype.addLoader = function addLoader() { } peer = this.createPeer({ - host: host, + host: addr, type: bcoin.peer.types.LOADER }); @@ -1186,7 +1182,7 @@ Pool.prototype.createPeer = function createPeer(options) { version.services.toString(2), version.agent); - bcoin.time.add(peer.host, version.ts); + bcoin.time.add(peer.hostname, version.ts); self.emit('version', version, peer); }); @@ -1365,7 +1361,7 @@ Pool.prototype.addLeech = function addLeech(socket) { Pool.prototype.addPeer = function addPeer() { var self = this; - var peer, host; + var peer, addr; if (!this.loaded) return; @@ -1377,13 +1373,13 @@ Pool.prototype.addPeer = function addPeer() { if (!this.peers.load) return; - host = this.hosts.getHost(); + addr = this.hosts.getHost(); - if (!host) + if (!addr) return; peer = this.createPeer({ - host: host, + host: addr, type: bcoin.peer.types.REGULAR }); @@ -1771,9 +1767,8 @@ Pool.prototype.setMisbehavior = function setMisbehavior(peer, score) { peer.banScore += score; if (peer.banScore >= constants.BAN_SCORE) { - this.hosts.ban(peer.host); + this.ban(peer); this.logger.debug('Ban threshold exceeded (%s).', peer.host); - peer.destroy(); return true; } @@ -1782,14 +1777,14 @@ Pool.prototype.setMisbehavior = function setMisbehavior(peer, score) { /** * Ban a peer. - * @param {String|NetworkAddress} host + * @param {NetworkAddress} host */ -Pool.prototype.ban = function ban(host) { - var peer = this.peers.get(host); +Pool.prototype.ban = function ban(addr) { + var peer = this.peers.get(addr); - this.logger.debug('Banning peer (%s).', host); - this.hosts.ban(host); + this.logger.debug('Banning peer (%s).', addr.hostname); + this.hosts.ban(addr); if (peer) peer.destroy(); @@ -1797,21 +1792,21 @@ Pool.prototype.ban = function ban(host) { /** * Unban a peer. - * @param {String|NetworkAddress} host + * @param {String|NetworkAddress} addr */ -Pool.prototype.unban = function unban(host) { - this.hosts.unban(host); +Pool.prototype.unban = function unban(addr) { + this.hosts.unban(addr); }; /** * Test whether the host/peer is banned. - * @param {String} host + * @param {NetworkAddress} addr * @returns {Boolean} */ -Pool.prototype.isMisbehaving = function isMisbehaving(host) { - return this.hosts.isMisbehaving(host); +Pool.prototype.isMisbehaving = function isMisbehaving(addr) { + return this.hosts.isMisbehaving(addr); }; /** @@ -1819,20 +1814,24 @@ Pool.prototype.isMisbehaving = function isMisbehaving(host) { * @param {Peer} peer */ -Pool.prototype.ignore = function ignore(peer) { - this.logger.debug('Ignoring peer (%s).', peer.hostname); - this.hosts.ignore(peer.host); - peer.destroy(); +Pool.prototype.ignore = function ignore(addr) { + var peer = this.peers.get(addr); + + this.logger.debug('Ignoring peer (%s).', addr.hostname); + this.hosts.ignore(addr); + + if (peer) + peer.destroy(); }; /** * Test whether the host/peer is ignored. - * @param {String} host + * @param {NetworkAddress} addr * @returns {Boolean} */ -Pool.prototype.isIgnored = function isIgnored(host) { - return this.hosts.isIgnored(host); +Pool.prototype.isIgnored = function isIgnored(addr) { + return this.hosts.isIgnored(addr); }; /** @@ -1915,14 +1914,15 @@ function PeerList(pool) { this.load = null; // All peers this.all = []; - // Map of hosts + // Map of hostnames this.map = {}; } PeerList.prototype.addPending = function addPending(peer) { this.pending.push(peer); this.all.push(peer); - this.map[peer.host] = peer; + assert(!this.map[peer.hostname]); + this.map[peer.hostname] = peer; }; PeerList.prototype.promote = function promote(peer) { @@ -1936,7 +1936,8 @@ PeerList.prototype.remove = function remove(peer) { utils.binaryRemove(this.leeches, peer, compare); utils.binaryRemove(this.all, peer, compare); - delete this.map[peer.host]; + assert(this.map[peer.hostname]); + delete this.map[peer.hostname]; if (this.load === peer) { this.pool.logger.info('Removed loader peer (%s).', peer.hostname); @@ -1946,11 +1947,11 @@ PeerList.prototype.remove = function remove(peer) { PeerList.prototype.repurpose = function repurpose(peer) { assert(peer.type === bcoin.peer.types.REGULAR); - peer.type = bcoin.peer.types.LOADER; utils.binaryRemove(this.pending, peer, compare); utils.binaryRemove(this.regular, peer, compare); - assert(!this.peer.load); - this.peers.load = peer; + peer.type = bcoin.peer.types.LOADER; + assert(!this.load); + this.load = peer; }; PeerList.prototype.isFull = function isFull() { @@ -1958,19 +1959,19 @@ PeerList.prototype.isFull = function isFull() { }; PeerList.prototype.addLeech = function addLeech(peer) { - this.peers.leeches.push(peer); - this.peers.all.push(peer); - this.peers.map[peer.host] = peer; + this.leeches.push(peer); + this.all.push(peer); + this.map[peer.hostname] = peer; }; PeerList.prototype.addLoader = function addLoader(peer) { this.load = peer; this.all.push(peer); - this.map[peer.host] = peer; + this.map[peer.hostname] = peer; }; -PeerList.prototype.get = function get(host) { - return this.map[host]; +PeerList.prototype.get = function get(addr) { + return this.map[addr.hostname]; }; PeerList.prototype.destroy = function destroy() { @@ -2030,15 +2031,15 @@ HostList.prototype.clear = function clear() { */ HostList.prototype.getLoaderHost = function getLoaderHost() { - var host = this.getRandom(this.seeds); + var addr = this.getRandom(this.seeds); - if (host) - return host; + if (addr) + return addr; - host = this.getRandom(this.items); + addr = this.getRandom(this.items); - if (host) - return host; + if (addr) + return addr; this.pool.logger.warning('All seeds banned or ignored. Clearing...'); this.clear(); @@ -2052,10 +2053,10 @@ HostList.prototype.getLoaderHost = function getLoaderHost() { */ HostList.prototype.getHost = function getHost() { - var host = this.getRandom(this.seeds, true); + var addr = this.getRandom(this.seeds, true); - if (host) - return host; + if (addr) + return addr; return this.getRandom(this.items, true); }; @@ -2070,22 +2071,22 @@ HostList.prototype.getHost = function getHost() { HostList.prototype.getRandom = function getRandom(hosts, unique) { var index = Math.random() * hosts.length | 0; var last = -1; - var i, host; + var i, addr; for (i = 0; i < hosts.length; i++) { - host = hosts[i]; + addr = hosts[i]; - if (this.isMisbehaving(host.host)) + if (this.isMisbehaving(addr)) continue; - if (this.isIgnored(host.host)) + if (this.isIgnored(addr)) continue; - if (unique && this.pool.peers.get(host.host)) + if (unique && this.pool.peers.get(addr)) continue; if (i >= index) - return host; + return addr; last = i; } @@ -2098,92 +2099,75 @@ HostList.prototype.getRandom = function getRandom(hosts, unique) { /** * Add host to host list. - * @param {String|NetworkAddress} host + * @param {NetworkAddress} addr * @returns {Boolean} */ -HostList.prototype.add = function add(host) { - if (typeof host === 'string') - host = NetworkAddress.fromHostname(host, this.network); - +HostList.prototype.add = function add(addr) { if (this.items.length > 500) return; - if (this.map[host.host]) + if (this.map[addr.hostname]) return; - utils.binaryInsert(this.items, host, compare); + utils.binaryInsert(this.items, addr, compare); - this.map[host.host] = host; + this.map[addr.hostname] = addr; - return host; + return addr; }; /** * Remove host from host list. - * @param {String|NetworkAddress} host + * @param {NetworkAddress} addr * @returns {Boolean} */ -HostList.prototype.remove = function remove(host) { - if (host.host) - host = host.host; +HostList.prototype.remove = function remove(addr) { + addr = this.map[addr.hostname]; - host = this.map[host]; - - if (!host) + if (!addr) return; - utils.binaryRemove(this.items, host, compare); + utils.binaryRemove(this.items, addr, compare); - delete this.map[host]; + delete this.map[addr.hostname]; - return host; + return addr; }; /** * Increase peer's ban score. - * @param {String} host + * @param {NetworkAddress} addr */ -HostList.prototype.ban = function ban(host) { - if (host.host) - host = host.host; - - this.misbehaving[host] = utils.now(); - this.remove(host); +HostList.prototype.ban = function ban(addr) { + this.misbehaving[addr.host] = utils.now(); + this.remove(addr); }; /** * Unban host. - * @param {String} host + * @param {NetworkAddress} addr */ -HostList.prototype.unban = function unban(host) { - if (host.host) - host = host.host; - - delete this.misbehaving[host]; - delete this.ignored[host]; +HostList.prototype.unban = function unban(addr) { + delete this.misbehaving[addr.host]; + delete this.ignored[addr.host]; }; /** * Test whether the host/peer is banned. - * @param {String} host + * @param {NetworkAddress} addr * @returns {Boolean} */ -HostList.prototype.isMisbehaving = function isMisbehaving(host) { - var time; - - if (host.host) - host = host.host; - - time = this.misbehaving[host]; +HostList.prototype.isMisbehaving = function isMisbehaving(addr) { + var time = this.misbehaving[addr.host]; if (time != null) { if (utils.now() > time + constants.BAN_TIME) { - delete this.misbehaving[host]; + delete this.misbehaving[addr.host]; return false; } return true; @@ -2194,28 +2178,22 @@ HostList.prototype.isMisbehaving = function isMisbehaving(host) { /** * Ignore peer. - * @param {Peer} peer + * @param {NetworkAddress} addr */ -HostList.prototype.ignore = function ignore(host) { - if (host.host) - host = host.host; - - if (!this.remove(host)) - this.ignored[host] = true; +HostList.prototype.ignore = function ignore(addr) { + if (!this.remove(addr)) + this.ignored[addr.host] = true; }; /** * Test whether the host/peer is ignored. - * @param {String} host + * @param {NetworkAddress} addr * @returns {Boolean} */ -HostList.prototype.isIgnored = function isIgnored(host) { - if (host.host) - host = host.host; - - return this.ignored[host] === true; +HostList.prototype.isIgnored = function isIgnored(addr) { + return this.ignored[addr.host] === true; }; /** diff --git a/lib/utils/ip.js b/lib/utils/ip.js index 1b9639a0..30d500c8 100644 --- a/lib/utils/ip.js +++ b/lib/utils/ip.js @@ -54,7 +54,10 @@ exports.parseHost = function parseHost(addr) { */ exports.hostname = function hostname(host, port) { - if (exports.version(host) === 6) + var version = exports.version(host); + if (version !== -1) + host = exports.normalize(host); + if (version === 6) host = '[' + host + ']'; return host + ':' + port; };