pool: refactor host and peer list.
This commit is contained in:
parent
159679e5eb
commit
0ff93dc705
@ -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
|
||||
|
||||
@ -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':
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
222
lib/net/pool.js
222
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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user