improve address management.
This commit is contained in:
parent
5ae0c441c1
commit
e2817436de
@ -171,6 +171,10 @@ exports.toString = function toString(ip) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
exports.normalize = function normalize(ip) {
|
exports.normalize = function normalize(ip) {
|
||||||
|
if (Buffer.isBuffer(ip)) {
|
||||||
|
assert(ip.length === 16);
|
||||||
|
return exports.toString(ip);
|
||||||
|
}
|
||||||
return exports.toString(exports.toBuffer(ip));
|
return exports.toString(exports.toBuffer(ip));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -20,18 +20,15 @@ var constants = bcoin.protocol.constants;
|
|||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @param {Function?} options.createSocket - Callback which returns a
|
* @param {Function?} options.createSocket - Callback which returns a
|
||||||
* node.js-like socket object. Necessary for browser.
|
* node.js-like socket object. Necessary for browser.
|
||||||
* @param {Boolean} priority - Whether this peer is high
|
|
||||||
* priority (i.e. a loader).
|
|
||||||
* @param {Chain} options.chain
|
* @param {Chain} options.chain
|
||||||
* @param {Mempool} options.mempool
|
* @param {Mempool} options.mempool
|
||||||
* @param {Number?} options.ts - Time at which peer was discovered (unix time).
|
* @param {Number?} options.ts - Time at which peer was discovered (unix time).
|
||||||
* @param {net.Socket?} options.socket
|
* @param {net.Socket?} options.socket
|
||||||
* @param {Seed?} options.seed - Host to connect to.
|
* @param {NetworkAddress?} options.host - Host to connect to.
|
||||||
* @property {Pool} pool
|
* @property {Pool} pool
|
||||||
* @property {net.Socket?} socket
|
* @property {net.Socket?} socket
|
||||||
* @property {String?} host
|
* @property {String?} host
|
||||||
* @property {Number} port
|
* @property {Number} port
|
||||||
* @property {Boolean} priority
|
|
||||||
* @property {Parser} parser
|
* @property {Parser} parser
|
||||||
* @property {Framer} framer
|
* @property {Framer} framer
|
||||||
* @property {Chain} chain
|
* @property {Chain} chain
|
||||||
@ -62,8 +59,6 @@ var constants = bcoin.protocol.constants;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function Peer(pool, options) {
|
function Peer(pool, options) {
|
||||||
var seed;
|
|
||||||
|
|
||||||
if (!(this instanceof Peer))
|
if (!(this instanceof Peer))
|
||||||
return new Peer(pool, options);
|
return new Peer(pool, options);
|
||||||
|
|
||||||
@ -79,7 +74,6 @@ function Peer(pool, options) {
|
|||||||
this.port = 0;
|
this.port = 0;
|
||||||
this.hostname = null;
|
this.hostname = null;
|
||||||
this._createSocket = this.options.createSocket;
|
this._createSocket = this.options.createSocket;
|
||||||
this.priority = this.options.priority;
|
|
||||||
this.chain = this.pool.chain;
|
this.chain = this.pool.chain;
|
||||||
this.mempool = this.pool.mempool;
|
this.mempool = this.pool.mempool;
|
||||||
this.network = this.chain.network;
|
this.network = this.chain.network;
|
||||||
@ -109,12 +103,11 @@ function Peer(pool, options) {
|
|||||||
|
|
||||||
if (options.socket) {
|
if (options.socket) {
|
||||||
this.socket = options.socket;
|
this.socket = options.socket;
|
||||||
this.host = this.socket.remoteAddress;
|
this.host = IP.normalize(this.socket.remoteAddress);
|
||||||
this.port = this.socket.remotePort;
|
this.port = this.socket.remotePort;
|
||||||
} else if (options.seed) {
|
} else if (options.host) {
|
||||||
seed = IP.parseHost(options.seed);
|
this.host = options.host.host;
|
||||||
this.host = seed.host;
|
this.port = options.host.port;
|
||||||
this.port = seed.port || this.network.port;
|
|
||||||
this.socket = this.createSocket(this.port, this.host);
|
this.socket = this.createSocket(this.port, this.host);
|
||||||
} else {
|
} else {
|
||||||
assert(false, 'No seed or socket.');
|
assert(false, 'No seed or socket.');
|
||||||
@ -122,12 +115,10 @@ function Peer(pool, options) {
|
|||||||
|
|
||||||
assert(typeof this.host === 'string');
|
assert(typeof this.host === 'string');
|
||||||
assert(typeof this.port === 'number');
|
assert(typeof this.port === 'number');
|
||||||
|
assert(this.socket, 'No socket.');
|
||||||
|
|
||||||
this.hostname = IP.hostname(this.host, this.port);
|
this.hostname = IP.hostname(this.host, this.port);
|
||||||
|
|
||||||
if (!this.socket)
|
|
||||||
throw new Error('No socket');
|
|
||||||
|
|
||||||
this.requests = {
|
this.requests = {
|
||||||
timeout: this.options.requestTimeout || 10000,
|
timeout: this.options.requestTimeout || 10000,
|
||||||
skip: {},
|
skip: {},
|
||||||
@ -295,14 +286,10 @@ Peer.prototype.createSocket = function createSocket(port, host) {
|
|||||||
socket = net.connect(port, host);
|
socket = net.connect(port, host);
|
||||||
}
|
}
|
||||||
|
|
||||||
bcoin.debug(
|
bcoin.debug('Connecting to %s.', hostname);
|
||||||
'Connecting to %s (priority=%s).',
|
|
||||||
hostname, this.priority);
|
|
||||||
|
|
||||||
socket.once('connect', function() {
|
socket.once('connect', function() {
|
||||||
bcoin.debug(
|
bcoin.debug('Connected to %s.', hostname);
|
||||||
'Connected to %s (priority=%s).',
|
|
||||||
hostname, self.priority);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return socket;
|
return socket;
|
||||||
@ -1380,34 +1367,24 @@ Peer.prototype._handleGetData = function _handleGetData(items) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Peer.prototype._handleAddr = function _handleAddr(addrs) {
|
Peer.prototype._handleAddr = function _handleAddr(addrs) {
|
||||||
|
var hosts = [];
|
||||||
var now = utils.now();
|
var now = utils.now();
|
||||||
var i, addr, ts;
|
var i, addr, ts;
|
||||||
|
|
||||||
for (i = 0; i < addrs.length; i++) {
|
for (i = 0; i < addrs.length; i++) {
|
||||||
addr = addrs[i];
|
addr = new NetworkAddress(addrs[i]);
|
||||||
|
|
||||||
ts = addr.ts;
|
|
||||||
|
|
||||||
if (ts <= 100000000 || ts > now + 10 * 60)
|
|
||||||
ts = now - 5 * 24 * 60 * 60;
|
|
||||||
|
|
||||||
this.addrFilter.add(addr.host, 'ascii');
|
this.addrFilter.add(addr.host, 'ascii');
|
||||||
|
hosts.push(addr);
|
||||||
this.emit('addr', {
|
|
||||||
version: addr.version,
|
|
||||||
ts: ts,
|
|
||||||
services: addr.services,
|
|
||||||
host: addr.host,
|
|
||||||
port: addr.port || this.network.port
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bcoin.debug(
|
bcoin.debug(
|
||||||
'Received %d addrs (seeds=%d, peers=%d) (%s).',
|
'Received %d addrs (hosts=%d, peers=%d) (%s).',
|
||||||
addrs.length,
|
hosts.length,
|
||||||
this.pool.seeds.length,
|
this.pool.hosts.length,
|
||||||
this.pool.peers.all.length,
|
this.pool.peers.all.length,
|
||||||
this.hostname);
|
this.hostname);
|
||||||
|
|
||||||
|
this.fire('addr', hosts);
|
||||||
};
|
};
|
||||||
|
|
||||||
Peer.prototype._handlePing = function _handlePing(data) {
|
Peer.prototype._handlePing = function _handlePing(data) {
|
||||||
@ -1448,38 +1425,22 @@ Peer.prototype._handlePong = function _handlePong(data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Peer.prototype._handleGetAddr = function _handleGetAddr() {
|
Peer.prototype._handleGetAddr = function _handleGetAddr() {
|
||||||
var hosts = {};
|
|
||||||
var items = [];
|
var items = [];
|
||||||
var ts = utils.now() - (process.uptime() | 0);
|
var i, host;
|
||||||
var i, seed;
|
|
||||||
|
|
||||||
if (this.pool.options.selfish)
|
if (this.pool.options.selfish)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < this.pool.seeds.length; i++) {
|
for (i = 0; i < this.pool.hosts.length; i++) {
|
||||||
seed = this.pool.seeds[i];
|
host = this.pool.hosts[i];
|
||||||
|
|
||||||
assert(typeof seed === 'object');
|
if (!host.isIP())
|
||||||
|
|
||||||
seed = this.pool.getPeer(seed.host) || seed;
|
|
||||||
|
|
||||||
if (IP.version(seed.host) === -1)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (hosts[seed.host])
|
if (!this.addrFilter.added(host.host, 'ascii'))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
hosts[seed.host] = true;
|
items.push(host);
|
||||||
|
|
||||||
if (!this.addrFilter.added(seed.host, 'ascii'))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
ts: seed.ts || ts,
|
|
||||||
services: seed.version ? seed.version.services : 0,
|
|
||||||
host: seed.host,
|
|
||||||
port: seed.port || this.network.port
|
|
||||||
});
|
|
||||||
|
|
||||||
if (items.length === 1000)
|
if (items.length === 1000)
|
||||||
break;
|
break;
|
||||||
@ -1675,6 +1636,125 @@ Peer.prototype.inspect = function inspect() {
|
|||||||
+ '>';
|
+ '>';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a network address.
|
||||||
|
* @exports NetworkAddress
|
||||||
|
* @constructor
|
||||||
|
* @private
|
||||||
|
* @param {NakedNetworkAddress} options
|
||||||
|
*/
|
||||||
|
|
||||||
|
function NetworkAddress(options) {
|
||||||
|
var host, ts, now;
|
||||||
|
|
||||||
|
if (!(this instanceof NetworkAddress))
|
||||||
|
return new NetworkAddress(options);
|
||||||
|
|
||||||
|
now = utils.now();
|
||||||
|
host = options.host;
|
||||||
|
ts = options.ts;
|
||||||
|
|
||||||
|
if (ts <= 100000000 || ts > now + 10 * 60)
|
||||||
|
ts = now - 5 * 24 * 60 * 60;
|
||||||
|
|
||||||
|
if (IP.version(host) !== -1)
|
||||||
|
host = IP.normalize(host);
|
||||||
|
|
||||||
|
assert(typeof host === 'string');
|
||||||
|
assert(typeof options.port === 'number');
|
||||||
|
assert(typeof options.services === 'number');
|
||||||
|
assert(typeof options.ts === 'number');
|
||||||
|
|
||||||
|
this.id = NetworkAddress.uid++;
|
||||||
|
this.host = host;
|
||||||
|
this.port = options.port;
|
||||||
|
this.services = options.services;
|
||||||
|
this.ts = ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkAddress.uid = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the `host` field is an ip address.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetworkAddress.prototype.isIP = function isIP() {
|
||||||
|
return IP.version(this.host) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the NETWORK service bit is set.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetworkAddress.prototype.hasNetwork = function hasNetwork() {
|
||||||
|
return (this.services & constants.services.NETWORK) !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the BLOOM service bit is set.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetworkAddress.prototype.hasBloom = function hasBloom() {
|
||||||
|
return (this.services & constants.services.BLOOM) !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the GETUTXO service bit is set.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetworkAddress.prototype.hasUTXO = function hasUTXO() {
|
||||||
|
return (this.services & constants.services.GETUTXO) !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the WITNESS service bit is set.
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetworkAddress.prototype.hasWitness = function hasWitness() {
|
||||||
|
return (this.services & constants.services.WITNESS) !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inspect the network address.
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetworkAddress.prototype.inspect = function inspect() {
|
||||||
|
return '<NetworkAddress:'
|
||||||
|
+ ' id=' + this.id
|
||||||
|
+ ' hostname=' + IP.hostname(this.host, this.port)
|
||||||
|
+ ' services=' + this.services.toString(2)
|
||||||
|
+ ' date=' + utils.date(this.ts)
|
||||||
|
+ '>';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a network address
|
||||||
|
* from a hostname (i.e. 127.0.0.1:8333).
|
||||||
|
* @param {String} hostname
|
||||||
|
* @param {(Network|NetworkType)?} network
|
||||||
|
* @returns {NetworkAddress}
|
||||||
|
*/
|
||||||
|
|
||||||
|
NetworkAddress.fromHostname = function fromHostname(hostname, network) {
|
||||||
|
var address = IP.parseHost(hostname);
|
||||||
|
network = bcoin.network.get(network);
|
||||||
|
return new NetworkAddress({
|
||||||
|
host: address.host,
|
||||||
|
port: address.port || network.port,
|
||||||
|
version: constants.VERSION,
|
||||||
|
services: constants.services.NETWORK
|
||||||
|
| constants.services.BLOOM
|
||||||
|
| constants.services.WITNESS,
|
||||||
|
ts: utils.now()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helpers
|
* Helpers
|
||||||
*/
|
*/
|
||||||
@ -1687,4 +1767,7 @@ function compare(a, b) {
|
|||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = Peer;
|
exports = Peer;
|
||||||
|
exports.NetworkAddress = NetworkAddress;
|
||||||
|
|
||||||
|
module.exports = exports;
|
||||||
|
|||||||
@ -12,6 +12,7 @@ var IP = require('./ip');
|
|||||||
var assert = utils.assert;
|
var assert = utils.assert;
|
||||||
var constants = bcoin.protocol.constants;
|
var constants = bcoin.protocol.constants;
|
||||||
var VerifyError = bcoin.errors.VerifyError;
|
var VerifyError = bcoin.errors.VerifyError;
|
||||||
|
var NetworkAddress = bcoin.peer.NetworkAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pool of peers for handling all network activity.
|
* A pool of peers for handling all network activity.
|
||||||
@ -45,7 +46,7 @@ var VerifyError = bcoin.errors.VerifyError;
|
|||||||
* Only deal with witness peers.
|
* Only deal with witness peers.
|
||||||
* @param {Boolean} [options.discoverPeers=true] Automatically discover new
|
* @param {Boolean} [options.discoverPeers=true] Automatically discover new
|
||||||
* peers.
|
* peers.
|
||||||
* @param {(String[]|Seed[])?} options.seeds
|
* @param {String[]} options.seeds
|
||||||
* @param {Function?} options.createSocket - Custom function to create a socket.
|
* @param {Function?} options.createSocket - Custom function to create a socket.
|
||||||
* Must accept (port, host) and return a node-like socket.
|
* Must accept (port, host) and return a node-like socket.
|
||||||
* @param {Function?} options.createServer - Custom function to create a server.
|
* @param {Function?} options.createServer - Custom function to create a server.
|
||||||
@ -75,6 +76,7 @@ var VerifyError = bcoin.errors.VerifyError;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function Pool(options) {
|
function Pool(options) {
|
||||||
|
var self = this;
|
||||||
var seeds;
|
var seeds;
|
||||||
|
|
||||||
if (!(this instanceof Pool))
|
if (!(this instanceof Pool))
|
||||||
@ -104,10 +106,12 @@ function Pool(options) {
|
|||||||
if (process.env.BCOIN_SEED)
|
if (process.env.BCOIN_SEED)
|
||||||
seeds.unshift(process.env.BCOIN_SEED);
|
seeds.unshift(process.env.BCOIN_SEED);
|
||||||
|
|
||||||
this.originalSeeds = seeds.map(IP.parseHost);
|
this.seeds = seeds.map(function(hostname) {
|
||||||
this.seeds = [];
|
return NetworkAddress.fromHostname(hostname, self.network);
|
||||||
this.hosts = {};
|
});
|
||||||
this.setSeeds([]);
|
|
||||||
|
this.hosts = [];
|
||||||
|
this.hostMap = {};
|
||||||
this.host = '0.0.0.0';
|
this.host = '0.0.0.0';
|
||||||
this.port = this.network.port;
|
this.port = this.network.port;
|
||||||
|
|
||||||
@ -246,7 +250,7 @@ Pool.prototype.connect = function connect() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.originalSeeds.length > 0) {
|
if (this.seeds.length > 0) {
|
||||||
this._addLoader();
|
this._addLoader();
|
||||||
|
|
||||||
for (i = 0; i < this.size - 1; i++)
|
for (i = 0; i < this.size - 1; i++)
|
||||||
@ -555,8 +559,7 @@ Pool.prototype._addLoader = function _addLoader() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
peer = this._createPeer({
|
peer = this._createPeer({
|
||||||
seed: this.getSeed(true),
|
host: this.getLoaderHost(),
|
||||||
priority: true,
|
|
||||||
network: true,
|
network: true,
|
||||||
spv: this.options.spv,
|
spv: this.options.spv,
|
||||||
witness: this.options.witness
|
witness: this.options.witness
|
||||||
@ -966,10 +969,9 @@ Pool.prototype._createPeer = function _createPeer(options) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var peer = new bcoin.peer(this, {
|
var peer = new bcoin.peer(this, {
|
||||||
seed: options.seed,
|
host: options.host,
|
||||||
createSocket: this.options.createSocket,
|
createSocket: this.options.createSocket,
|
||||||
relay: this.options.relay,
|
relay: this.options.relay,
|
||||||
priority: options.priority,
|
|
||||||
socket: options.socket,
|
socket: options.socket,
|
||||||
network: options.network,
|
network: options.network,
|
||||||
spv: options.spv,
|
spv: options.spv,
|
||||||
@ -1021,34 +1023,38 @@ Pool.prototype._createPeer = function _createPeer(options) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.on('addr', function(data) {
|
peer.on('addr', function(hosts) {
|
||||||
|
var i, host;
|
||||||
|
|
||||||
if (self.options.discoverPeers === false)
|
if (self.options.discoverPeers === false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(data.services & constants.services.NETWORK))
|
for (i = 0; i < hosts.length; i++) {
|
||||||
return;
|
host = hosts[i];
|
||||||
|
|
||||||
if (self.options.headers) {
|
if (!host.hasNetwork())
|
||||||
if (data.version < 31800)
|
continue;
|
||||||
return;
|
|
||||||
|
if (self.options.headers) {
|
||||||
|
if (!host.hasHeaders())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.options.spv) {
|
||||||
|
if (!host.hasBloom())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.options.witness) {
|
||||||
|
if (!host.hasWitness())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.addHost(host))
|
||||||
|
self.emit('host', host, peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.options.spv) {
|
self.emit('addr', hosts, peer);
|
||||||
if (data.version < 70011 || !(data.services & constants.services.BLOOM))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.options.witness) {
|
|
||||||
if (!(data.services & constants.services.WITNESS))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.seeds.length > 300)
|
|
||||||
self.setSeeds(self.seeds.slice(-150));
|
|
||||||
|
|
||||||
self.addSeed(data);
|
|
||||||
|
|
||||||
self.emit('addr', data, peer);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.on('txs', function(txs) {
|
peer.on('txs', function(txs) {
|
||||||
@ -1148,7 +1154,6 @@ Pool.prototype._addLeech = function _addLeech(socket) {
|
|||||||
|
|
||||||
peer = this._createPeer({
|
peer = this._createPeer({
|
||||||
socket: socket,
|
socket: socket,
|
||||||
priority: false,
|
|
||||||
network: false,
|
network: false,
|
||||||
spv: false,
|
spv: false,
|
||||||
witness: false,
|
witness: false,
|
||||||
@ -1195,7 +1200,7 @@ Pool.prototype._addLeech = function _addLeech(socket) {
|
|||||||
|
|
||||||
Pool.prototype._addPeer = function _addPeer() {
|
Pool.prototype._addPeer = function _addPeer() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var peer, seed;
|
var peer, host;
|
||||||
|
|
||||||
if (this.destroyed)
|
if (this.destroyed)
|
||||||
return;
|
return;
|
||||||
@ -1203,16 +1208,15 @@ Pool.prototype._addPeer = function _addPeer() {
|
|||||||
if (this.peers.regular.length + this.peers.pending.length >= this.size - 1)
|
if (this.peers.regular.length + this.peers.pending.length >= this.size - 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
seed = this.getSeed(false);
|
host = this.getHost();
|
||||||
|
|
||||||
if (!seed) {
|
if (!host) {
|
||||||
setTimeout(this._addPeer.bind(this), 5000);
|
setTimeout(this._addPeer.bind(this), 5000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
peer = this._createPeer({
|
peer = this._createPeer({
|
||||||
seed: seed,
|
host: host,
|
||||||
priority: false,
|
|
||||||
network: true,
|
network: true,
|
||||||
spv: this.options.spv,
|
spv: this.options.spv,
|
||||||
witness: this.options.witness
|
witness: this.options.witness
|
||||||
@ -1838,12 +1842,12 @@ Pool.prototype.destroy = function destroy(callback) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get peer by host.
|
* Get peer by host.
|
||||||
* @param {Seed|String} addr
|
* @param {String} addr
|
||||||
* @returns {Peer?}
|
* @returns {Peer?}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.getPeer = function getPeer(host) {
|
Pool.prototype.getPeer = function getPeer(host) {
|
||||||
return this.peers.map[host.host || host];
|
return this.peers.map[host];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1853,7 +1857,23 @@ Pool.prototype.getPeer = function getPeer(host) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.getUTXOs = function getUTXOs(utxos, callback) {
|
Pool.prototype.getUTXOs = function getUTXOs(utxos, callback) {
|
||||||
var peer = this.peers.load || this.peers.regular[0];
|
var i, peer;
|
||||||
|
|
||||||
|
if (this.peers.load && this.peers.load.version) {
|
||||||
|
if (this.peers.load.version.services & constants.services.BLOOM)
|
||||||
|
peer = this.peers.load;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!peer) {
|
||||||
|
for (i = 0; i < this.peers.regular.length; i++) {
|
||||||
|
peer = this.peers.regular[i];
|
||||||
|
if (peer.version.services & constants.services.BLOOM)
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (i === this.peers.regular.length)
|
||||||
|
peer = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!peer)
|
if (!peer)
|
||||||
return utils.asyncify(callback)(new Error('No peer available.'));
|
return utils.asyncify(callback)(new Error('No peer available.'));
|
||||||
@ -1867,7 +1887,7 @@ Pool.prototype.getUTXOs = function getUTXOs(utxos, callback) {
|
|||||||
* @param {Function} callback - Returns [Error, {@link TX}].
|
* @param {Function} callback - Returns [Error, {@link TX}].
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.fillHistory = function fillHistory(tx, callback) {
|
Pool.prototype.fillCoins = function fillCoins(tx, callback) {
|
||||||
var utxos = [];
|
var utxos = [];
|
||||||
var i, input;
|
var i, input;
|
||||||
|
|
||||||
@ -1891,135 +1911,119 @@ Pool.prototype.fillHistory = function fillHistory(tx, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate a new seed which is not currently being used.
|
* Allocate a new loader host.
|
||||||
* @param {Boolean?} priority - If true, the peer that
|
* @returns {NetworkAddress}
|
||||||
* is going to use this seed is high-priority.
|
|
||||||
* @returns {Seed}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.getSeed = function getSeed(priority) {
|
Pool.prototype.getLoaderHost = function getLoaderHost() {
|
||||||
var addr;
|
var host;
|
||||||
|
|
||||||
if (priority) {
|
if (!this.connected)
|
||||||
if (!this.connected)
|
return this.seeds[0];
|
||||||
return this.originalSeeds[0];
|
|
||||||
|
|
||||||
addr = this._getRandom(this.originalSeeds);
|
host = this.getRandom(this.seeds);
|
||||||
if (addr)
|
if (host)
|
||||||
return addr;
|
return host;
|
||||||
|
|
||||||
addr = this._getRandom(this.seeds);
|
return this.getRandom(this.hosts);
|
||||||
if (addr)
|
};
|
||||||
return addr;
|
|
||||||
|
|
||||||
addr = this.seeds[Math.random() * this.seeds.length | 0];
|
/**
|
||||||
if (addr)
|
* Allocate a new host which is not currently being used.
|
||||||
return addr;
|
* @returns {NetworkAddress}
|
||||||
|
*/
|
||||||
|
|
||||||
return this.originalSeeds[Math.random() * this.originalSeeds.length | 0];
|
Pool.prototype.getHost = function getHost() {
|
||||||
}
|
var host;
|
||||||
|
|
||||||
// Hang back if we don't have a loader peer yet.
|
// Hang back if we don't have a loader peer yet.
|
||||||
if (!this.peers.load)
|
if (!this.peers.load)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
addr = this._getRandom(this.originalSeeds, true);
|
host = this.getRandom(this.seeds, true);
|
||||||
if (addr)
|
if (host)
|
||||||
return addr;
|
return host;
|
||||||
|
|
||||||
addr = this._getRandom(this.seeds, true);
|
return this.getRandom(this.hosts, true);
|
||||||
if (addr)
|
|
||||||
return addr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype._getRandom = function _getRandom(seeds, uniq) {
|
/**
|
||||||
|
* Get a random host from collection of hosts.
|
||||||
|
* @param {NetworkAddress[]} hosts
|
||||||
|
* @param {Boolean} unique
|
||||||
|
* @returns {NetworkAddress}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Pool.prototype.getRandom = function getRandom(hosts, unique) {
|
||||||
var tried = {};
|
var tried = {};
|
||||||
var tries = 0;
|
var tries = 0;
|
||||||
var index, addr;
|
var index, host;
|
||||||
|
|
||||||
|
if (!unique)
|
||||||
|
return hosts[Math.random() * hosts.length | 0];
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (tries === seeds.length)
|
if (tries === hosts.length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
index = Math.random() * seeds.length | 0;
|
index = Math.random() * hosts.length | 0;
|
||||||
addr = seeds[index];
|
host = hosts[index];
|
||||||
|
|
||||||
if (!tried[index]) {
|
if (!tried[index]) {
|
||||||
tried[index] = true;
|
tried[index] = true;
|
||||||
tries++;
|
tries++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isMisbehaving(addr.host))
|
if (this.getPeer(host.host))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (uniq && this.getPeer(addr.host))
|
return host;
|
||||||
continue;
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset seeds list.
|
* Add host to host list.
|
||||||
* @param {String[]|Seed[]} seeds
|
* @param {String|NetworkAddress} host
|
||||||
*/
|
|
||||||
|
|
||||||
Pool.prototype.setSeeds = function setSeeds(seeds) {
|
|
||||||
var i;
|
|
||||||
|
|
||||||
this.seeds = [];
|
|
||||||
this.hosts = {};
|
|
||||||
|
|
||||||
for (i = 0; i < seeds.length; i++)
|
|
||||||
this.addSeed(seeds[i]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add seed to seed list.
|
|
||||||
* @param {String|Seed} seed
|
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.addSeed = function addSeed(seed) {
|
Pool.prototype.addHost = function addHost(host) {
|
||||||
seed = IP.parseHost(seed);
|
if (typeof host === 'string')
|
||||||
|
host = NetworkAddress.fromHostname(host);
|
||||||
|
|
||||||
if (this.hosts[seed.host] != null)
|
if (this.hosts.length > 500)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
this.seeds.push({
|
if (this.hostMap[host.host])
|
||||||
host: seed.host,
|
return;
|
||||||
port: seed.port || this.network.port
|
|
||||||
});
|
|
||||||
|
|
||||||
this.hosts[seed.host] = true;
|
utils.binaryInsert(this.hosts, host, compare);
|
||||||
|
|
||||||
return true;
|
this.hostMap[host.host] = host;
|
||||||
|
|
||||||
|
return host;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove seed from seed list.
|
* Remove host from host list.
|
||||||
* @param {String|Seed} seed
|
* @param {String|NetworkAddress} host
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Pool.prototype.removeSeed = function removeSeed(seed) {
|
Pool.prototype.removeHost = function removeHost(host) {
|
||||||
var i;
|
if (host.host)
|
||||||
|
host = host.host;
|
||||||
|
|
||||||
seed = IP.parseHost(seed);
|
host = this.hostMap[host];
|
||||||
|
|
||||||
if (this.hosts[seed.host] == null)
|
if (!host)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < this.seeds.length; i++) {
|
utils.binaryRemove(this.hosts, host, compare);
|
||||||
if (this.seeds[i].host === seed.host) {
|
|
||||||
this.seeds.splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete this.hosts[seed.host];
|
delete this.hostMap[host];
|
||||||
|
|
||||||
return true;
|
return host;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2034,6 +2038,7 @@ Pool.prototype.setMisbehavior = function setMisbehavior(peer, score) {
|
|||||||
|
|
||||||
if (peer.banScore >= constants.BAN_SCORE) {
|
if (peer.banScore >= constants.BAN_SCORE) {
|
||||||
this.peers.misbehaving[peer.host] = utils.now();
|
this.peers.misbehaving[peer.host] = utils.now();
|
||||||
|
this.removeHost(peer.host);
|
||||||
bcoin.debug('Ban threshold exceeded (%s).', peer.host);
|
bcoin.debug('Ban threshold exceeded (%s).', peer.host);
|
||||||
peer.destroy();
|
peer.destroy();
|
||||||
return true;
|
return true;
|
||||||
@ -2056,7 +2061,7 @@ Pool.prototype.isMisbehaving = function isMisbehaving(host) {
|
|||||||
|
|
||||||
time = this.peers.misbehaving[host];
|
time = this.peers.misbehaving[host];
|
||||||
|
|
||||||
if (time) {
|
if (time != null) {
|
||||||
if (utils.now() > time + constants.BAN_TIME) {
|
if (utils.now() > time + constants.BAN_TIME) {
|
||||||
delete this.peers.misbehaving[host];
|
delete this.peers.misbehaving[host];
|
||||||
peer = this.getPeer(host);
|
peer = this.getPeer(host);
|
||||||
|
|||||||
@ -416,7 +416,7 @@ Framer.prototype.feeFilter = function feeFilter(options) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize an address.
|
* Serialize an address.
|
||||||
* @param {NetworkAddress} data
|
* @param {NakedNetworkAddress} data
|
||||||
* @param {Boolean?} full - Whether to include the timestamp.
|
* @param {Boolean?} full - Whether to include the timestamp.
|
||||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||||
@ -1163,7 +1163,7 @@ Framer.reject = function reject(details, writer) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an addr packet (without a header).
|
* Create an addr packet (without a header).
|
||||||
* @param {NetworkAddress[]} hosts
|
* @param {NakedNetworkAddress[]} hosts
|
||||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1176,7 +1176,7 @@ Parser.parseReject = function parseReject(p) {
|
|||||||
/**
|
/**
|
||||||
* Parse serialized network address.
|
* Parse serialized network address.
|
||||||
* @param {Buffer|BufferReader} p
|
* @param {Buffer|BufferReader} p
|
||||||
* @returns {NetworkAddress}
|
* @returns {NakedNetworkAddress}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Parser.parseAddress = function parseAddress(p, full) {
|
Parser.parseAddress = function parseAddress(p, full) {
|
||||||
@ -1206,7 +1206,7 @@ Parser.parseAddress = function parseAddress(p, full) {
|
|||||||
/**
|
/**
|
||||||
* Parse addr packet.
|
* Parse addr packet.
|
||||||
* @param {Buffer|BufferReader} p
|
* @param {Buffer|BufferReader} p
|
||||||
* @returns {NetworkAddress[]}
|
* @returns {NakedNetworkAddress[]}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Parser.parseAddr = function parseAddr(p) {
|
Parser.parseAddr = function parseAddr(p) {
|
||||||
|
|||||||
@ -46,13 +46,6 @@
|
|||||||
* @global
|
* @global
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} Seed
|
|
||||||
* @property {String} host
|
|
||||||
* @property {Number} port
|
|
||||||
* @global
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of addresses ({@link Base58Address} -> value).
|
* A map of addresses ({@link Base58Address} -> value).
|
||||||
* @typedef {Object} AddressMap
|
* @typedef {Object} AddressMap
|
||||||
@ -255,7 +248,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} NetworkAddress
|
* @typedef {Object} NakedNetworkAddress
|
||||||
* @property {Number?} ts - Timestamp.
|
* @property {Number?} ts - Timestamp.
|
||||||
* @property {Number?} services - Service bits.
|
* @property {Number?} services - Service bits.
|
||||||
* @property {String?} host - IP address (IPv6 or IPv4).
|
* @property {String?} host - IP address (IPv6 or IPv4).
|
||||||
@ -268,8 +261,8 @@
|
|||||||
* @property {Number} version - Protocol version.
|
* @property {Number} version - Protocol version.
|
||||||
* @property {Number} services - Service bits.
|
* @property {Number} services - Service bits.
|
||||||
* @property {Number} ts - Timestamp of discovery.
|
* @property {Number} ts - Timestamp of discovery.
|
||||||
* @property {NetworkAddress} local - Our address.
|
* @property {NakedNetworkAddress} local - Our address.
|
||||||
* @property {NetworkAddress} remote - Their address.
|
* @property {NakedNetworkAddress} remote - Their address.
|
||||||
* @property {BN} nonce
|
* @property {BN} nonce
|
||||||
* @property {String} agent - User agent string.
|
* @property {String} agent - User agent string.
|
||||||
* @property {Number} height - Chain height.
|
* @property {Number} height - Chain height.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user