pool: refactor host and peer list.

This commit is contained in:
Christopher Jeffrey 2016-08-25 19:30:56 -07:00
parent 159679e5eb
commit 0ff93dc705
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 132 additions and 130 deletions

View File

@ -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

View File

@ -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':

View File

@ -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}

View File

@ -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);
};
/**

View File

@ -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;
};
/**

View File

@ -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;
};